https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93923
--- Comment #2 from Jonathan Wakely <redi at gcc dot gnu.org> --- You can make the program valid by ensuring you do not try to do the is_constructible when performing overload resolution for copy initialization of B: #include <type_traits> class A; template<typename T> struct B { template<typename... Args> static constexpr bool not_copy_constructor_candidate = sizeof...(Args) != 1 || (std::is_same_v<B, Args> && ...); template< class... Args, std::enable_if_t<not_copy_constructor_candidate<Args...>, int> = 0, std::enable_if_t<std::is_constructible<T, Args...>::value, int> = 0 > B(Args && ... args) {} }; struct A { A(const B<A>&) {} }; int main() { static_assert(std::is_copy_constructible<A>::value, ""); } I think GCC is correct to reject the original code.