https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93923
Jonathan Wakely <redi at gcc dot gnu.org> changed: What |Removed |Added ---------------------------------------------------------------------------- Resolution|--- |INVALID Status|UNCONFIRMED |RESOLVED --- Comment #7 from Jonathan Wakely <redi at gcc dot gnu.org> --- I'm going to close this, for the reason stated earlier: the standard says you can't use is_constructible with an incomplete type. Performing overload resolution for is_copy_constructible<A> has to check if A(const B<A>&) is viable, which tries to construct B<A> from const A&, which has to check the constraints of B<A>::B(Args&&...) which depends on is_constructible<A, const A&>. I'm not convinced this example is very realistic, but if needed it can be fixed by excluding the B(Args&&...) constructor from being used with a single argument of type T: template<typename T> struct B { template<class T1, class... Args> struct check : std::is_constructible<T1, Args...> { }; template<class T1, class Arg1> struct check<T1, Arg1> : std::is_same<T1, std::decay_t<Arg1>> { }; template< class... Args, std::enable_if_t<check<T, Args...>::value, int> = 0> B(Args && ... args) {} B(const T&) { } B(T&&) { } }; Alternatively, just make the B(Args&&...) constructor explicit (and add a separate default constructor, because explicit default constructors are weird and unhelpful), which is probably the right thing to do anyway: template<typename T> struct B { template< class... Args, std::enable_if_t<std::is_constructible<T, Args...>::value, int> = 0 > explicit B(Args && ... args) {} B() = default; }; If you have a realistic use case that can't be solved in one of these ways, and shows a reasonable situation where is_constructible needs to work for incomplete types, please provide it and re-open the bug.