如何与模板类的构造函数成为朋友?

Kyl*_*yle 6 c++ gcc templates constructor friend

为什么

class A;
template<typename T> class B
{
private: 
    A* a;

public:  
    B();
};


class A : public B<int>
{
private:    
    friend B<int>::B<int>();
    int x;
};


template<typename T>
B<T>::B()
{
    a = new A;
    a->x = 5;
}

int main() { return 0; }
Run Code Online (Sandbox Code Playgroud)

造成

../src/main.cpp:15:错误:无效使用构造函数作为模板
../src/main.cpp:15:注意:使用'B :: B'而不是'B :: class B'来在限定名称中命名构造函数

尚未改变friend B<int>::B<int>()friend B<int>::B()结果

../src/main.cpp:15:错误:没有在类'B'中声明的'void B :: B()'成员函数

完全删除模板

class A;
class B
{
private:
    A* a;

public:
    B();
};


class A : public B
{
private:
    friend B::B();
    int x;
};


B::B()
{
    a = new A;
    a->x = 5;
}

int main() { return 0; }
Run Code Online (Sandbox Code Playgroud)

编译并执行得很好 - 尽管我的IDE说朋友B :: B()是无效的语法?

Jam*_*lis 5

根据CWG缺陷147的分辨率(分辨率已合并到C++ 03中),命名类模板特化的非模板构造函数的正确方法是:

B<int>::B();
Run Code Online (Sandbox Code Playgroud)

并不是

B<int>::B<int>();
Run Code Online (Sandbox Code Playgroud)

如果允许后者,那么当你有一个类模板特化的构造函数模板特化时会有一个歧义:第二个<int>是类模板还是构造函数模板?(有关详细信息,请参阅上面链接的缺陷报告)

因此,将类模板特化的构造函数声明为朋友的正确方法是:

friend B<int>::B();
Run Code Online (Sandbox Code Playgroud)

Comeau 4.3.10.1和Intel C++ 11.1都接受这种形式.Visual C++ 2008和Visual C++ 2010都不接受该表单,但都接受(不正确)表单friend B<int>::B<int>();(我将在Microsoft Connect上提交缺陷报告).

gcc不接受4.5版之前的任何一种形式. 针对gcc 3.0.2报告了错误5023,但错误报告中请求的解决方案是无效表单.看来bug 9050的解决方案也解决了这个问题,gcc 4.5接受了正确的表格.Georg Fritzsche在对该问题的评论中对此进行了验证.