9

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.

max66
  • 65,235
  • 10
  • 71
  • 111
  • You can simplify your code by removing `template ` and get the same error with GCC. –  May 05 '18 at 21:36
  • @NeilButterworth - I know: in that case, I have the same error with both compilers. – max66 May 05 '18 at 21:38
  • 3
    For extra fun: https://godbolt.org/g/y7mtWX Regardless of what the standard says, surely this has to be a clang bug as well, it makes no sense that changing the order of the `f0` and `f1` definitions changes the result without any diagnostic whatsoever. –  May 05 '18 at 21:39
  • 2
    Even more fun: If you declare the function in global namespace: `template void bar();` and leave just *one* variable, then call to `bar();` compiles on GCC and results in 'undefined reference' on Clang. – HolyBlackCat May 05 '18 at 21:46
  • [Related](https://stackoverflow.com/a/44268181/2752075): *"CWG agreed that such techniques (stateful template metaprogramming by defining friend functions in templates) should be ill-formed, although the mechanism for prohibiting them is as yet undetermined."* I wasn't able to find one, but maybe there is some related defect report? – HolyBlackCat May 05 '18 at 21:49
  • @hvd - surprising; seems that the second definition cover the first one. – max66 May 05 '18 at 21:51
  • Currently clang has some problems with friends, see [bug 33222](https://llvm.org/pr33222). Probably related – Rakete1111 May 05 '18 at 21:51

1 Answers1

6

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.

bogdan
  • 9,229
  • 2
  • 33
  • 48