friend declaration of template specialization fails
Asked Answered
I

1

9

The following code containing friend declaration fails with indicated error (see http://ideone.com/Kq5dy):

template<class T> void foo() {}

template<typename T>
class A {
   void foo();
   friend void foo<T>(); // error: variable or field 'foo' declared void
};

int main()
{
   foo<int>();
}

If the order of friend declaration and member function declaration reversed, then the code compiles without problems (see http://ideone.com/y3hiK):

template<class T> void foo() {}

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

int main()
{
   foo<int>();
}

This doesn't happen if the friend declaration doesn't contain template specialization: non-template friends are ok, as well as a template friends. Also using qualified name in template specialization allows code to compile. My question is why does the first example fail? It seems compiler looking up names in class scope at the point of friend declaration and only for template specialization? Where in the Standard this behavior is specified?

Ineluctable answered 15/12, 2011 at 3:48 Comment(0)
T
7

To make it explicit that it's that function you want to be-friend prepend the function name with :: to say that it's in the global namespace.

Snippet that compiles and does what you want:

template<class T> void foo() {}

template<typename T>
class A {
   void foo();
   friend void ::foo<T>();
};

int main()
{
   foo<int>();
}

n1905.pdf

3.4/9 Name Lookup

Name lookup for a name used in the definition of a friend function (11.4) defined inline in the class granting friendship shall proceed as described for lookup in member function definitions. If the friend function is not defined in the class granting friendship, name lookup in the friend function definition shall proceed as described for lookup in namespace member function definitions

Your snippet fails to compile because of the same reason as the code below fails to compile.

template<class T> void foo () {}

template<typename T>
struct A { 

  void foo (); 

  void func () {
    foo<T> (); // when performing the name lookup A::foo is
               // found before ::foo<T>
  }
};

...

14.5.3 Friends [temp.friend] 1

A friend of a class or class template can be a function template or class template, a specialization of a function template or class template, or an ordinary (non-template) function or class. For a friend function declaration that is not a template declaration:

— if the name of the friend is a qualified or unqualified template-id, the friend declaration refers to a specialization of a function template, otherwise

— if the name of the friend is a qualified-id and a matching non-template function is found in the specified class or namespace, the friend declaration refers to that function, otherwise,

— if the name of the friend is a qualified-id and a matching specialization of a function template is found in the specified class or namespace, the friend declaration refers to that function template specialization, otherwise,

— the name shall be an unqualified-id that declares (or redeclares) an ordinary (non-template) function.

Thracian answered 15/12, 2011 at 3:50 Comment(7)
I mentioned that qualifying the friend specialization allows it to compile. I'm not looking for workarounds, I'm looking for the place in the Standard that explains why the first exxample fails.Ineluctable
@GeneBushuyev Then I'll try to look it up for you, sorry about the misunderstanding.Tine
No you didn't. "qualified-id" is blah::blub (or even ::blub), so your bold part doesn't apply. The code in the OP is unqualified.Bliss
I know that place in the standard, it doesn't answer the question why the first example fails.Ineluctable
Yes I'm sure. §A.4 [gram.expr], look under "qualified-id".Bliss
3.4/9 deals with name used in the definition of a friend function, not the function name itself.Lowry
No, your example is not related to the original problem. It deals with a template argument dependent function call, which has different lookup rules. You can swap func() and foo() and get the same result.Ineluctable

© 2022 - 2024 — McMap. All rights reserved.