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?
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With