8

The code

template <typename T>
void foo(const T& t)
{}

template <typename T>
class A
{
    template <>
    friend void foo<T>(const T& t)
    {}
};

gives compile error

"defining explicit specialization ‘foo<T>’ in friend declaration friend void foo<T>(const T& t)"

when compiling with gcc and

"error C3637: 'A<int>::foo' : a friend function definition cannot be a specialization of a unction template"

when compiling in VS2013

I understand that standard says so, but why? I want to understand the reason(under the hood) There are many articles where written "An explicit specialization cannot be a friend declaration.", but I can't understand why. Any ideas?

  • 1
    gcc reports `explicit specialization in non-namespace scope 'struct A'` and `template-id 'foo' in declaration of primary template` for the given code. – eerorika Jan 04 '15 at 15:41
  • sorry I copy paste from another source – Vahagn Babajanyan Jan 04 '15 at 15:42
  • Explicit specializations prevent implicit instantiation. Every time you instantiate `A` for a new set of template arguments, you'd add another explicit specialization of `foo`. It is ill-formed, No Diagnostic Required, to add that specialization if `foo` has already been implicitly instantiated for the same template arguments [temp.expl.spec]/6. – dyp Jan 04 '15 at 15:48
  • @dyp if I understand clearly your comment, it is true for every function template specialization in class template, not only for friends? but compile errors are about friend function specialization. I think there is something special for friends, besides mentioned in your comment – Vahagn Babajanyan Jan 07 '15 at 19:30
  • This is true for any kind of template (implicit instantiation before explicit specialization with the same template arguments is ill-formed, NDR). The way new explicit specializations would be added by the code you've shown however make it very likely for such violations to occur, since a) the new specializations would be added implicitly and b) in another scope than the primary template. – dyp Jan 07 '15 at 19:59

1 Answers1

7

Declaring an explicit specialization inside a class template for the first (and possibly only) time would mean that the explicit specialization is only "existing" once the template has been instantiated - regardless from whether the declaration is dependent on a template parameter or not. This creates many problems and would cause violations of the ODR in various scenarios, many of which would be presumably ill-formed NDR; Mainly because of the paragraph mentioned by @dyp in the comments, [temp.expl.spec]/6

Moreover, a friend function definition inside a class without an exterior declaration makes this function only invokeable via ADL. Clearly it would be absolutely nonsensical if an explicit specialization is only applicable when the call has associating argument types - again, not to mention the violations of the ODR.

Those and other reasons make such a construct far too complicated too allow, while not being very beneficial: What you can simply do is adding the specialization as a friend, not in any way indicating whether this specialization is instantiated or explicitly specialized.

friend void foo<T>(const T&);

Any explicit specialization can then be added in namespace-scope.

Columbo
  • 60,038
  • 8
  • 155
  • 203
  • Or you could overload, by defining a non-template friend function inside. – dyp Jan 04 '15 at 16:37
  • For completeness, a friend function definition inside a class does generally allow the function to be invoked without ADL, just not using the in-class declaration. As long as an out-of-class declaration is available, it's fine, so: `struct S { friend void f() { } } void f(); int main() { f(); }` is perfectly valid. But, explicit template specialisations need those explicit specialisations to be declared whenever they are used, so an in-class declaration would not be good enough. –  Jan 04 '15 at 18:13
  • 1
    @Columbo Thanks for answer but could you please explain ADL case more clearly, I don't understand the problem. If function template specialization defined in class then it should take an argument of the class or a class derived from that, as ADL mechanism should work. So what is the problem with template specialization definition with such(class or derived) argument? – Vahagn Babajanyan Jan 08 '15 at 18:16