【问题标题】:In C++, why isn't it possible to friend a template class member function using the template type of another class?在 C++ 中,为什么不能使用另一个类的模板类型来为模板类成员函数加好友?
【发布时间】:2017-02-03 18:33:36
【问题描述】:

换句话说,为什么编译得很好:

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

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

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

虽然不是这样:

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
}

对于第二个代码 sn-p,编译器(gcc 6.2,没有特殊标志)说:

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(){

据我了解,在第二个代码 sn-p 中,当声明 var 时,编译器应该解析 B 类声明,将朋友声明中使用的 Type 替换为 int,一切正常。我错过了什么?

编辑:下面的 cmets 指出第二个代码 sn-p 似乎可以使用 clang 和 Visual C++ 2015 正确编译

【问题讨论】:

  • 仅供参考。它似乎用clang编译
  • 它还可以使用 Visual C++ 2015 编译,您可以在这里尝试:webcompiler.cloudapp.net
  • 适用于 clang 3.8 和 gcc 6.1.0 Demo

标签: c++ templates friend


【解决方案1】:

B&lt;int&gt; 在用于A&lt;int&gt;::f() 之前的显式实例化可解决此问题。我假设 GCC 在A&lt;int&gt;::f() 的定义中尝试隐式实例化B&lt;int&gt;。但是A&lt;int&gt;::f() 的定义还没有完成,GCC '松开' 朋友声明。看起来像是编译器的问题。

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>();
}

【讨论】:

    【解决方案2】:

    专门化template class成员函数而不专门化整个template class是允许专门化非template成员函数的特殊情况,所以可能GCC很困惑,我不知道原因,但是不知何故,您不能向template class 的专业非template 成员声明友谊。临时解决方案是专门化整个 class template 以使其正常工作。

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

    然后,定义A&lt;int&gt;::f

    对于class B:

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

    对于template class B

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

    但我觉得Clang就在这里,这样的朋友声明应该没有问题。这可能是GCC 中的一个错误。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-04-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-06
      • 1970-01-01
      相关资源
      最近更新 更多