Here's the output for GCC:
type_traits:1302:66: error: incomplete type 'A' used in type trait expression
: public integral_constant<bool, __is_base_of(_Base, _Derived)>
^
<source>:5:51: note: in instantiation of template class 'std::is_base_of<Base, A>' requested here
template <class T, typename = std::enable_if<std::is_base_of<Base, T>::value>>
^
<source>:10:5: note: in instantiation of default argument for 'B<A>' required here
B<A> b;
^~~~
<source>:8:7: note: definition of 'A' is not complete until the closing '}'
class A : public Base
^
Indeed, A is incomplete until the closing } has been reached. You use A in the type traits while instantiating B<A> inside A, so you're out of luck there.
What you can do instead is to enforce it with a static_assert in a member function of B:
template <class T>
class B {
public:
B() {
static_assert(std::is_base_of<Base, T>::value, "T must inherit from base");
}
};
Inside member functions, all types are complete.
typename std::enable_if<...>::type.std::enable_ifitself will never SFINAE out, it's itstypemember that is dynamically disabled.B<A, void> b;to bypass the detection. Not pretty, but at least it's still active everywhere else.