The various standard type traits querying whether a type is constructible are implemented (in both libc++ and libstdc++) as ultimately delegating to an intrinsic such as __is_constructible. This trait fails to account for default member initializers, which produce a hard error rather than returning a true/false answer when evaluating the intrinsic, and hence the trait. Example: #include <type_traits> template <class T> struct Wrap { Wrap() = default; T data{}; // default member initializer }; struct NoDefault { NoDefault(NoDefault const&) {} // non-trivial, not an aggregate }; int main() { using namespace std; static_assert(!is_default_constructible<Wrap<NoDefault>>::value, "bad"); } Godbolt link for quick experimentation: https://godbolt.org/z/-D9mpA This fails with both libc++ and libstdc++, for all dialects of C++11 and later, for all online compilers up to and including trunk.
SFINAE only applies to instantiating the declaration of a function template specialization (and a few other things not relevant here). It does not apply to triggering the implicit definition of a defaulted constructor, nor to determining whether a defaulted constructor would be implicitly deleted. It doesn't appear to me that Clang is doing anything wrong here. If you want this case to become valid, I think the right core issue to file would be to suggest that [class.default.ctor]/2 should say that a defaulted default constructor is defined as deleted if it's in a templated class and instantiation of any default member initializer results in an invalid type or expression in the immediate context of the instantiation. (That is, add a brand new kind of SFINAE for this case.) CWG2202 is doing something similar for default arguments, so this is not unprecedented.
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96645 Is there a same bug as in GCC? Tried to compile this code: template<bool B> struct bool_constant { static constexpr bool value = B; using type = bool_constant; }; using true_type = bool_constant<true>; template<typename T> struct is_default_constructible : bool_constant<__is_constructible(T)> { }; void testVarStruct() { struct DataWithStruct { struct A { int number = 5; // compiles, if remove initialization }; is_default_constructible<A>::type t = true_type{}; }; } Output: <source>:22:47: error: no viable conversion from 'bool_constant<true>' to 'bool_constant<false>' is_default_constructible<A>::type t = true_type{};
Re comment#2, that's not the same as this issue. Default member initializers are not parsed until the closing brace of the outermost enclosing class they're nested within -- the default member initializer for A is not parsed until we reach the end of DataWithStruct. As a consequence (in particular, because we can't compute the exception specification for the default constructor until we've parsed the default member initializers, and in general we never form a call to a function until after we know its exception specification), default construction of an `A` fails in the context of the type of DataWithStruct::t. So that's not a bug. Given the original problem is also not a bug, I'm going to resolve this INVALID. We can reopen it or open a new bug if the committee decides to do something SFINAE-like for default member initializers.