Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

std::vector etc unnecessarily (erroneously?) instantiates nested template argument type

The following code compiles fine, even tough std::plus<void> would be illegal (in C++11).

template < typename > struct data {};
data<std::plus<void>> x; // does not attempt to complete std::plus<void>

which makes sense because data<std::plus<void>> does not need to instantiate std::plus<void>. However, it fails to compile when constructing a std::vector, which somehow causes instantiation of std::plus<void>.

std::vector<data<std::plus<void>>> v;

The error is:

/opt/local/libexec/llvm-3.5/bin/../include/c++/v1/functional:496:29: error: cannot form a reference to 'void'
_Tp operator()(const _Tp& __x, const _Tp& __y) const
/opt/local/libexec/llvm-3.5/bin/../include/c++/v1/type_traits:2055:27: note: in instantiation of
template class 'std::__1::plus<void>' requested here
decltype(__is_constructible_test(declval<_Tp>(), declval<_Args>()...))

A similar error on g++4.8 or with std::list.

Is this expected behavior?

like image 737
Hui Avatar asked Oct 20 '22 07:10

Hui


1 Answers

The following code compiles fine, even tough std::plus<void> would be illegal (in C++11).

Since C++1y the standard garantees the following explicit specialization to be made:

template <> struct plus<void> {
    template <class T, class U> constexpr auto operator()(T&& t, U&& u) const
    -> decltype(std::forward<T>(t) + std::forward<U>(u));

    typedef unspecified is_transparent;
};

The problem for actually incomplete template arguments (like void for std::plus in C++11) is:

In particular, the effects are undefined in the following cases:

— if an incomplete type (3.9) is used as a template argument when instantiating a template component, unless specifically allowed for that component.

The reason why your programm encounters undefined behavior is that std::plus is instantiated with void which is an incomplete type.

The reason why writing

std::plus<void> p;

does not cause a compiler error (whilst causing UB) is that the member function of a template is not instantiated until used.

like image 183
Columbo Avatar answered Nov 04 '22 01:11

Columbo