【问题标题】:Make Friend the constructor of a template class将 Friend 设为模板类的构造函数
【发布时间】:2015-09-02 01:35:30
【问题描述】:

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

我有一个类模板Foo,它采用布尔值B 作为模板参数。 我想交朋友,在 Foo 的实例中,模板参数为 b,Foo 的另一个实例的构造函数,参数为 !b,代码如下:

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

我真的不明白如何使它工作,感谢任何帮助了解问题所在。

【问题讨论】:

    标签: c++ templates


    【解决方案1】:

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

    我认为您的情况是有问题的,因为Foo&lt;true&gt;Foo&lt;false&gt; 的成员函数有一个朋友声明,而该声明又引用了Foo&lt;true&gt; 的成员函数。虽然成员分别在成员函数之前声明,但编译器不支持这种循环引用。 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&lt;!B&gt; 的实例化点是在 Foo&lt;B&gt; 的实例化点之前,除非我们应用 DR287 中的规则,否则看不到 Foo&lt;B&gt; 的构造函数声明。

    Friend 类或函数可以在类模板中声明。当一个模板被实例化时,它的朋友的名字被视为在它的实例化点已经显式声明了特化


    除此之外,还有另一个问题:Foo&lt;!B&gt;::Foo(Foo&lt;B&gt;&amp;); 指的是构造函数吗?如果它引用注入的类名,则它是对构造函数的引用,然后编译器必须将其视为这些上下文中的构造函数。所以编译器必须解析Foo&lt;!B&gt;::Foo。但是Foo&lt;!B&gt; 是一个依赖类型,所以编译器无法查看它来决定它是什么类型的名称(记住struct A { int A; } 是允许的,编译器必须验证它不在这种情况下)。我认为由于这些原因,cland 无法解析您的模板,因为它对 friend Foo&lt;!B&gt;::Foo(Foo&lt;B&gt;&amp;) 的含义感到困惑。

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

    【讨论】:

    • 非常感谢您提供的信息丰富的回复。所以我唯一的办法仍然是将整个 Class 模板实例声明为朋友,对吧?
    • @user 正确,我想是的。但也许您可以将需要私有访问的代码移至成员函数并与成员函数交朋友
    • 哦,我喜欢你将代码移动到另一个成员函数中的想法,我会看看我是否可以做一些看起来不错的事情。非常感谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-05
    • 2011-05-08
    • 1970-01-01
    • 1970-01-01
    • 2019-03-14
    相关资源
    最近更新 更多