Reputation: 66200
Another question of type "who's right between g++ and clang++?" for C++ standard gurus.
The following code
template <int>
struct foo
{
template <typename>
friend void bar ()
{ }
};
int main ()
{
foo<0> f0;
foo<1> f1;
}
compile without problem with clang++ (only two "unused variable" warnings) but give a the following error
tmp_002-11,14,gcc,clang.cpp: In instantiation of ‘struct foo<1>’:
tmp_002-11,14,gcc,clang.cpp:27:12: required from here
tmp_002-11,14,gcc,clang.cpp:20:16: error: redefinition of ‘template<class> void bar()’
friend void bar ()
^~~
tmp_002-11,14,gcc,clang.cpp:20:16: note: ‘template<class> void bar()’ previously defined here
compiling with g++.
The question, as usual, is: who's right ? g++ or clang++ ?
Checked with clang++ 3.9.1 and g++ 6.3.0 in my Debian platform. But, trying in Wandbox, seems equals with more recent versions.
Upvotes: 10
Views: 454
Reputation: 9317
GCC is right in this case.
The relevant standard wording is in [temp.inst]/2:
The implicit instantiation of a class template specialization causes
— the implicit instantiation of the declarations, but not of the definitions, of the non-deleted class member functions, member classes, scoped member enumerations, static data members, member templates, and friends; and
[...]
However, for the purpose of determining whether an instantiated redeclaration is valid according to 6.2 and 12.2, a declaration that corresponds to a definition in the template is considered to be a definition. [ Example: [...]template<typename T> struct Friendly { template<typename U> friend int f(U) { return sizeof(T); } }; Friendly<char> fc; Friendly<float> ff; // ill-formed: produces second definition of f(U)
— end example ]
The parts related to friends were added to this paragraph by DR2174 and published in C++17 (it's a defect report, so compilers should apply it to previous standard versions as well).
Recent versions of MSVC and EDG in strict mode also reject the code, complaining about a redefinition.
[temp.inject]/1 is somewhat related, but it only talks about friend functions, not friend function templates:
Friend classes or functions can be declared within a class template. When a template is instantiated, the names of its friends are treated as if the specialization had been explicitly declared at its point of instantiation.
Upvotes: 6