简体   繁体   English

交朋友模板类的构造函数

[英]Make Friend the constructor of a template class

Recently I started to use template. 最近,我开始使用模板。 And I just dump in a compile error. 而我只是转储了一个编译错误。

I have a Class Template Foo which take a boolean B as a template parameter. 我有一个类模板Foo ,它使用布尔B作为模板参数。 And I'm trying to make friend, in an instentiation of Foo with template argument b , the Constructor of the other instantiation of Foo with argument !b with this code: 而且我正在尝试通过模板参数bFoo的意图中结交朋友,并使用以下代码将!b参数的Foo的另一个实例化的构造方法:

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

The compiler return me these errors: 编译器向我返回这些错误:

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.

I compiled it with the following command: clang++ -std=c++11 foo.cpp on Windows. 我使用以下命令对其进行了编译:Windows上的clang++ -std=c++11 foo.cpp

I really don't understand how to make it work, any help to understand what's wrong is appreciated. 我真的不知道如何使它起作用,感谢您对任何理解错误的帮助。

I was commenting on someone else's answer and they asked me to paste my analysis here. 我在评论别人的答案,他们要我在这里粘贴我的分析。

I think that your case is problematic because Foo<true> has a friend declaration to Foo<false> 's member function which in turn refers to Foo<true> 's member function. 我认为您的情况是有问题的,因为Foo<true>Foo<false>的成员函数有一个朋友声明,而后者又引用了Foo<true>的成员函数。 While the members respectively are declared before the member functions, this kind of circular reference is not supported by compilers. 虽然分别在成员函数之前声明成员,但是编译器不支持这种循环引用。 GCC complains at instantiation 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>&);

This error message is a bit confusing, because it suggests that incomplete types could not be used with :: , which is wrong. 此错误消息有些令人困惑,因为它表明::不能使用不完整的类型,这是错误的。 A class that is being defined can be used with :: even if it is incomplete yet. 被定义的类可以与::一起使用,即使它还不完整。 A class however that is being instantiated is handled differently by GCC than a class that is being defined, and refering back to the class that is being instantiated in a qualified name is not supported by GCC apparently. 但是,GCC对正在实例化的类的处理与所定义的类不同,并且GCC显然不支持引用以合格名称实例化的类。

We have a DR about such cyclic references, http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#287 which would appear to make this legal, but as the final statement notes, "This needs work", so GCC is in its right to reject your code I would say. 我们提供了有关此类循环引用的DR, 网址为http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#287 ,这似乎使该声明合法,但作为最后声明,“这需要工作”,因此我要说的是,GCC有权拒绝您的代码。 To add to that confusion, we also have an explicit rule for names used in friend function declarations, which isn't mentioned in DR287 and its "as if" would make your code ill-formed because Foo<!B> 's point of instantiation is immediately before the point of instantiation of Foo<B> and unless we apply the rule in DR287 cannot see the constructor declaration of Foo<B> . 更令人困惑的是,我们还为朋友函数声明中使用的名称制定了明确的规则,DR287中没有提及该规则,并且“好像”会使您的代码格式错误,因为Foo<!B>的观点是实例化紧邻Foo<B>的实例化点之前,并且除非我们在DR287中应用该规则,否则无法看到Foo<B>的构造函数声明。

Friend classes or functions can be declared within a class template. 朋友类或函数可以在类模板中声明。 When a template is instantiated, the names of its friends are treated as if the specialization had been explicitly declared at its point of instantiation 实例化模板时,将其朋友的名称视为已在实例化点明确声明了专门化名称


Independent of this, there's another issue at hand: Is Foo<!B>::Foo(Foo<B>&); 独立于此,还有另一个问题:是Foo<!B>::Foo(Foo<B>&); referring to a constructor? 指一个构造函数? It is a reference to the constructor if it refers to the injected class name, which the compiler then must treat as the constructor in these constexts. 如果引用注入的类名,则它是对构造函数的引用,然后在这些上下文中,编译器必须将其视为构造函数。 So the compiler must resolve Foo<!B>::Foo . 因此,编译器必须解析Foo<!B>::Foo But Foo<!B> is a dependent type, so the compiler cannot look into it to decide what kind of name it is (remember that struct A { int A; } is allowed, and the compiler has to verify it is not in such a situation). 但是Foo<!B>是从属类型,因此编译器无法调查它来决定它的名称(请记住,允许使用struct A { int A; } ,并且编译器必须验证它是否不在此类型中。情况)。 I think for these reasons, cland fails to parse your template because it is confused as to what friend Foo<!B>::Foo(Foo<B>&) means. 我认为由于这些原因,cland 无法解析您的模板,因为它对于friend Foo<!B>::Foo(Foo<B>&)含义感到困惑。

I believe the template itself (disregarding issues of instantiation) should be well-formed because the compiler could just delay the lookup of Foo<!B>::Foo and take it as a non-type which it actually is (constructors). 认为模板本身(不考虑实例化问题)应该是格式正确的,因为编译器可能会延迟对Foo<!B>::Foo的查找,并将其视为实际上不是构造函数的非类型。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM