Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

friend a template specialization without <>

C++03 and C++11 have in the first paragraph of [temp.friend]:

[Edited quote. First try missed a second difference in wording.]

For a friend function declaration that is not a template declaration:

  1. 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

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

  3. [C++03:] 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,

    [C++11:] if the name of the friend is a qualified-id and and a matching function template is found in the specified class or namespace, the friend declaration refers to the deduced specialization of that function template, otherwise,

  4. the name shall be an unqualified-id that declares (or redeclares) an ordinary (nontemplate) function.

[The change in wording looks like clarification to me. Though I guess there might be different ways to interpret the C++03 wording about "finding a specialization in a class or namespace".]

I'm curious about that third bullet. I wrote this code to try to match its requirements, but both g++ 4.8.1 and clang++ 3.4 reject the code, whether with -std=c++03 or -std=c++11:

template <class T> class R;
namespace N {
    template <class T> void test(const R<T>&);
}

template <class T>
class R {
    friend void N::test(const R<T>&);  // 8
    int m;
};

template <class T>
void N::test(const R<T>& rec) { rec.m; }

int main() {
    R<int> r;
    N::test(r);
}

Of course if I change line 8 to

friend void N::test<>(const R<T>&);

the first bullet applies and the program is accepted. g++ prints a helpful warning saying the friend "declares a non-template function" and suggesting I might want to do exactly that. The code would probably get more style points for clarity and safety, too.

But shouldn't the code above be covered by the third bullet and valid? The friend declaration is not a template declaration and uses a qualified-id which is not a template-id as the name. And there is no nontemplate function declaration to match for the second bullet.

Is this just a compiler bug common to both? Or have I misunderstood something, and if so, is there an example of a program that does demonstrate that third bullet?

like image 335
aschepler Avatar asked Oct 18 '13 21:10

aschepler


1 Answers

at line //8, modified code as : friend void N::test< R<T> >( R<T>&); correct too.

friend void N::test<R<T>>(const R<T>&);//one type is friend with one type  #1
friend void N::test<>(const R<T>&);// one type is friend with one type    #2

I use some code proof that #1 is equal to #2

At last, I try to answer your question .I am not sure that is right.

 friend void N::test(const R<T>&);

When instantiating the class R, R<T> is a known type . However , the function is

declared as a friend function and really do not instantiate a function template , then the

friend function is a function that does not exist . From the point of view of grammar , the

compiler will prompt you that it is a function rather than a template

N::test (r);

In this place the function is instantiated, but the compiler does not match with a

friend before the declaration in R class , because you do not declare as a template in R

class, you just declare a function.

like image 163
Ron Tang Avatar answered Oct 21 '22 01:10

Ron Tang