Whats wrong with this:
#include <type_traits>
struct A;
template<typename T>
struct B
{
template<typename=std::enable_if<std::is_copy_constructible<T>::value>>
void f1() {}
};
template<typename T>
struct C {};
// Type your code here, or load an example.
int main() {
// Following fails
B<A> b;
// Could use this:
// b.f1<C>();
// This complies
C<A> c;
return 0;
}
/* This to be in or not doesn't make a difference
struct A
{};
*/
I tried this here: https://godbolt.org/z/NkL44s with different compilers:
So why do more recent compilers reject this? When instantiating B<A>
it is not clear in which form f1
will be used or if it will be used at all. So why the compiler complains about it? Shouldn't the f1
member template function be checked only if it is really used?
Edit:
As mentioned in comments, I made an unintented mistake in above code: std::enable_if
should have been std::enable_if_t
, as in this corrected playground: https://godbolt.org/z/cyuB3d
This changes the picture of compilers passing this code without error:
However, the question remains: Why does a defaulted template parameter of a function that is never used lead to compilation failure?
To instantiate a template function explicitly, follow the template keyword by a declaration (not definition) for the function, with the function identifier followed by the template arguments. template float twice<float>(float original); Template arguments may be omitted when the compiler can infer them.
When a function template is first called for each type, the compiler creates an instantiation. Each instantiation is a version of the templated function specialized for the type. This instantiation will be called every time the function is used for the type.
Member functions can be function templates in several contexts. All functions of class templates are generic but aren't referred to as member templates or member function templates. If these member functions take their own template arguments, they're considered to be member function templates.
The act of creating a new definition of a function, class, or member of a class from a template declaration and one or more template arguments is called template instantiation.
The reason is that std::is_constructible
requires a complete type: (Table 42)
Template
template <class T> struct is_copy_constructible;
Preconditions
T
shall be a complete type, cv void, or an array of unknown bound.
Failing to meet a library "shall" requirement results in undefined behavior.
From cppreference on is_copy_constructible<T>
:
T shall be a complete type, (possibly cv-qualified) void, or an array of unknown bound. Otherwise, the behavior is undefined.
So it seems like you have just plain UB in older compiler versions while the newer ones are nice enough to tell you that A
has to be a complete type.
Note that in the presence of UB, compliers are not reuqired to issue an error, but they may do it, which is a nice thing.
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