简体   繁体   中英

In C++, why isn't it possible to friend a template class member function using the template type of another class?

In other words, why does this compile fine :

template<typename Type>
class A{
  public:
    void f();
};

class B{
  friend void A<int>::f();
};

template<>
void A<int>::f(){
  B* var = new B();
}

While this doesn't :

template<typename Type>
class A{
  public:
    void f();
};

template<typename Type> // B is now a templated class
class B{
  friend void A<Type>::f(); // Friending is done using B templated type
};

template<>
void A<int>::f(){
  B<int>* var = new B<int>(); // var is now declared using int as its templated type
}

For the second code snippet, compiler (gcc 6.2, no special flags) says:

main.cpp: In instantiation of ‘class B<int>’:
main.cpp:14:28:   required from here
main.cpp:9:15: error: prototype for ‘void A<int>::f()’ does not match any in class ‘A<int>’
   friend void A<Type>::f();
               ^~~~~~~
main.cpp:13:6: error: candidate is: void A<Type>::f() [with Type = int]
 void A<int>::f(){

As I understand it, in the second code snippet, when declaring var the compiler should parse B class declaration, replace the Type used in the friend declaration by int, and everything should work fine. What am I missing?

EDIT : comments below have pointed out that the second code snippet seems to compile correctly with clang and Visual C++ 2015

An explicit instantiation of B<int> before it is used in A<int>::f() resolves this problem. I assume GCC tries an implicit instantiation of B<int> in the definition of A<int>::f() . But the definition of A<int>::f() is not finished and GCC 'looses' the friend declaration. It looks like a compiler problem.

template<typename Type>
class A
{
public:
    void f();
};

template<typename Type> // B is now a templated class
class B
{
    friend void A<Type>::f(); // Friending is done using B templated type
};

template
class B<int>; // <= explicit instantiation, that works

template<>
void A<int>::f()
{
    B<int>* var = new B<int>();
}

Specializing template class member function without specializing whole template class is special case when you are allowed to specialize non- template member function, so maybe GCC is confused, and I don't know the reasons, but somehow you can't declare friendship to specialized non- template member of template class . Temporary solution would be to specialize whole class template for this to work.

//class template A
template<typename Type>
class A{
  public:
    void f();
};

//class A<int>
template<>
class A<int>{
  public:
    void f();
};

Then, define A<int>::f :

For class B:

void A<int>::f(){
      B* var = new B();
      (void)(var);
}

For template class B :

void A<int>::f(){
      B<int>* var = new B<int>();
      (void)(var);
}

But I think Clang is right here, there should be no problems for such friend declaration. It's probably a bug in GCC .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM