GCC 7.3.0 (as well as 8.1 and 9.0 from godbolt.org) fails to compile the following code: //--- template<int N_> struct Foo { static constexpr int N = N_;// this indirection causes the error using Self = Foo<N>; Foo(const Self&) = default; }; //--- The error message reads > file.cpp:6:22: error: ‘Foo<N_>::Foo(const Self&)’ cannot be defaulted I used the following command line to obtain that error message: > g++ -Wall -Wextra -std=c++11 file.cpp
ICC rejects it for the same reason, but I don't see any justification for that in the standard. Clang accepts it.
We reject the code because defaultable_fn_check doesn't like the copy ctor: it asks copy_fn_p whether it is a copy ctor but it doesn't think so: 12997 else if (TYPE_REF_P (arg_type) 12998 && !TYPE_REF_IS_RVALUE (arg_type) 12999 && TYPE_MAIN_VARIANT (TREE_TYPE (arg_type)) == DECL_CONTEXT (d)) here both the main variant and the context are "struct Foo", but they compare unequal. Will poke some more at this.
MSVC also rejects it for the same reason as GCC (and ICC). Which makes clang the one which is different than all others.
I just ran into this (it's one of the examples of vendor divergence in P2953R0). https://isocpp.org/files/papers/P2953R0.html#corner-cases // https://godbolt.org/z/sxv5rvn8o template<class> struct C { C& operator=(std::add_lvalue_reference_t<const C>) = default; }; C<int> cl; GCC 13 says: error: 'C< <template-parameter-1-1> >& C< <template-parameter-1-1> >::operator=(std::add_lvalue_reference_t<const C< <template-parameter-1-1> > >)' cannot be defaulted 5 | C& operator=(std::add_lvalue_reference_t<const C>) = default; | ^~~~~~~ I confirm Andrew's observation that Clang is the odd one out in accepting this code (GCC, MSVC, EDG all reject). But it also seems pretty obvious that it should be accepted. Brian Bi concurs: "I couldn't figure out any reason why this shouldn't be valid." Or again something like this: template<bool B> struct C { C(std::conditional_t<B, const C&, C&&>) = default; C(std::conditional_t<B, C&&, const C&>); }; static_assert(std::is_trivially_copy_constructible_v<C<true>>); static_assert(std::is_trivially_move_constructible_v<C<false>>); GCC+EDG+MSVC reject; Clang accepts; and I think Clang is the conforming one. A related situation is // https://godbolt.org/z/1bhEx1Gr1 template<class... Ts> struct C { template<class T> using A = const C&; C(A<Ts>...) = default; // this is a default ctor or a copy ctor, depending on sizeof...(Ts) }; static_assert(std::is_trivially_constructible_v<C<>>); static_assert(std::is_trivially_copy_constructible_v<C<int>>); GCC rejects; Clang+EDG+MSVC accept; and I think Clang+EDG+MSVC are conforming.