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

时间:2015-08-29 10:37:11

标签: c++ templates

最近我开始使用模板。 我只是在编译错误中转储。

我有一个类模板Foo,它以布尔B作为模板参数。 而且我试图通过模板参数Foob进行交流,使用此代码使用参数!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

我真的不明白如何使它发挥作用,任何帮助,以了解什么是错误的。

1 个答案:

答案 0 :(得分:4)

我正在评论其他人的答案,他们让我在此处粘贴我的分析。

我认为您的案例存在问题,因为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这似乎使这个合法,但正如最后的声明所指出的那样,&#34;这需要工作&#34;,因此GCC有权我会拒绝你的代码。为了增加这种混淆,我们还对友元函数声明中使用的名称有一个明确的规则,在DR287及其&#34;中没有提到过,好像&#34;会使你的代码格式错误,因为Foo<!B>的实例化点紧接在Foo<B>的实例化之前,除非我们在DR287中应用规则,否则无法看到{{{}的构造函数声明1}}。

  

可以在类模板中声明好友类或函数。实例化模板时,其朋友的名称被视为专业化已在实例化时明确声明

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

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