使Friend成为模板类的构造函数

Make Friend the constructor of a template class

本文关键字:构造函数 Friend      更新时间:2023-10-16

最近我开始使用模板。我只是转储了一个编译错误。

我有一个类模板Foo,它采用布尔B作为模板参数。我试着交一个朋友,在带有模板参数bFoo的实例化中,带有参数!b的Foo的另一个实例化的构造函数,代码是:

template<bool B>
class Foo
{
public:
    Foo(Foo<!B>&);
private:
    friend Foo<!B>::Foo(Foo<B>&);
};

编译器返回以下错误:

test.cpp:22:18: error: C++ requires a type specifier for all declarations
        friend Foo<!B>::Foo(Foo<B>&);
        ~~~~~~          ^
test.cpp:22:18: error: constructor cannot have a return type
        friend Foo<!B>::Foo(Foo<B>&);
                        ^~~
2 errors generated.

我用以下命令编译了它:在Windows上使用clang++ -std=c++11 foo.cpp

我真的不知道如何让它发挥作用,任何帮助我理解错误的地方都是值得感激的。

我在评论别人的回答,他们让我把我的分析粘贴到这里。

我认为您的情况有问题,因为Foo<true>Foo<false>的成员函数有一个友元声明,而该友元声明又引用了Foo<true>的成员函数。虽然成员分别在成员函数之前声明,但编译器不支持这种循环引用。GCC在实例化时抱怨

main.cpp: In instantiation of 'class Foo<false>':
main.cpp:9:12:   required from 'class Foo<true>'
main.cpp:15:49:   required from here
main.cpp:9:12: error: invalid use of incomplete type 'class Foo<true>'
    friend Foo<!B>::Foo(Foo<B>&);

这个错误消息有点令人困惑,因为它表明不完整的类型不能与::一起使用,这是错误的。正在定义的类可以与::一起使用,即使它还不完整。然而,GCC对正在实例化的类的处理与正在定义的类不同,并且GCC显然不支持以限定名称引用回正在实例化的类别。

我们有一个关于这种循环引用的DR,http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#287这似乎使其合法,但正如最后声明所指出的,"这需要工作",所以GCC有权拒绝您的代码。更令人困惑的是,我们还有一个关于友元函数声明中使用的名称的显式规则,DR287中没有提到它,它的"好像"会使代码格式错误,因为Foo<!B>的实例化点就在Foo<B>的实例化点之前,除非我们在DR287中应用该规则,否则无法看到Foo<B>的构造函数声明。

友元类或函数可以在类模板中声明。当一个模板被实例化时,它的朋友的名字被视为在其实例化时明确声明了专门化


与此无关,还有另一个问题:Foo<!B>::Foo(Foo<B>&);是指构造函数吗?如果它引用了注入的类名,那么它就是对构造函数的引用,编译器必须将其视为这些constext中的构造函数。因此编译器必须解析Foo<!B>::Foo。但Foo<!B>是一个依赖类型,因此编译器无法查看它来决定它是什么类型的名称(请记住,struct A { int A; }是允许的,编译器必须验证它不处于这种情况(。我认为由于这些原因,cland无法解析您的模板,因为它对friend Foo<!B>::Foo(Foo<B>&)的含义感到困惑。

我相信模板本身(忽略实例化问题(应该是良好的形式,因为编译器可能会延迟Foo<!B>::Foo的查找,并将其视为实际的非类型(构造函数(。