Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

g++ and clang++ different behaviour with friend template function defined inside a template class

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.

like image 976
max66 Avatar asked May 05 '18 21:05

max66


1 Answers

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.

like image 76
bogdan Avatar answered Oct 10 '22 18:10

bogdan