简体   繁体   English

如何使模板参数的构造函数成为朋友?

[英]How do I make a template parameter's constructor a friend?

In C++11, they made it possible to friend a template parameter simply with friend T . 在C ++ 11中,他们可以简单地与friend T模板参数。 You can also friend methods within that parameter with friend T::Method() . 您还可以使用friend T::Method()在该参数中使用friend T::Method()

However, how do you friend a template parameter's constructor? 但是,你如何与模板参数的构造函数相关联?

class BeMyFriend
{
public:
 BeMyFriend& operator=(const BeMyFriend& rhs) = default;
 BeMyFriend(const BeMyFriend& rhs) = default;
};

template<class T>
class Test
{
 friend T& T::operator=(const T&); //Works fine, no error
 friend T::T(const T&); //error: prototype for 'BeMyFriend::BeMyFriend(const BeMyFriend&)' does not match any in class 'BeMyFriend'
};

int main()
{
 Test<BeMyFriend> hmm;

 return 0;
}

I'm able to friend the template parameter's operator= just fine, but I'm unable to friend T::T(const T&) . 我能够模板参数的operator=很好,但我不能交朋友T::T(const T&)

How can I make friend T::T(const T&); 我怎样才能成为friend T::T(const T&); work? 工作?


edit: This appears to be a different issue than what is solved in Make Friend the constructor of a template class . 编辑:这似乎与Make Friend在模板类的构造函数中解决的问题不同。 The issue there is dealing with circular template parameters in a declaration. 那里的问题是在声明中处理循环模板参数。 It doesn't deal with the constructor of an actual template parameter. 它不处理实际模板参数的构造函数。

The type of the Foo is a normal templated class, not a template parameter like T in my example. Foo的类型是普通的模板化类,而不是像我的例子中的T这样的模板参数。 Something like friend Foo<B>::Foo<B>() from that submission should compile just fine, unlike the issue I'm having here with friend T::T(const T&) . 像那个提交的friend Foo<B>::Foo<B>()这样的东西应该编译得很好,不像我和friend T::T(const T&)这里的问题。

edit: In case this ends up mattering, I'm compiling with gcc 7.2. 编辑:如果这最终成为问题,我正在使用gcc 7.2进行编译。

edit: I also want to clarify that C++ does support making constructors friends. 编辑:我还想澄清一下,C ++确实支持让构造函数成为朋友。 For example, friend X::X(char), X::~X(); 例如, friend X::X(char), X::~X(); in the first example at http://en.cppreference.com/w/cpp/language/friend . http://en.cppreference.com/w/cpp/language/friend的第一个例子中。

The issue here is how to make a template parameter's constructor a friend. 这里的问题是如何使模板参数的构造函数成为朋友。

Somehow I think T::T(const T&) isn't well parsed by the compiler because it doesn't consider the namespace T:: before the member constructor T() as a reference to some external class, obviously seen in error console ISO C++ forbids declaration of 'T' with no type and prototype for 'BeMyFriend::BeMyFriend(const BeMyFriend&)' does not match any in class 'BeMyFriend' where the compiler is blatantly trying to get any definition or declaration exported from outside the class, thus T:: should be forced by the user to get introduced to the compiler referenced to the befriended class like so T&:: this is sufficient to remove ambiguity. 不知怎的,我认为编译器没有很好地解析T::T(const T&) ,因为它不会将成员构造函数T()之前的名称空间T::视为对某些外部类的引用,这显然可以在错误控制台中看到ISO C++ forbids declaration of 'T' with no typeprototype for 'BeMyFriend::BeMyFriend(const BeMyFriend&)' does not match any in class 'BeMyFriend'中的prototype for 'BeMyFriend::BeMyFriend(const BeMyFriend&)' does not match any in class 'BeMyFriend'其中编译器公然试图获取从类外部导出的任何定义或声明因此T::应该被用户强制引入引用到友好类的编译器,这样T&::这足以消除歧义。

You can check here that the instantiator "works" perfectly and the value is properly befriended. 你可以在这里检查实例化器是否“完美地工作”并且值正确地结合了。

If, neverthless, you see in this example the error shown std::__cxx11::string Test<BeMyFriend>::mything' is private within this context areyoumyfriend.mything; 如果,无论如何,你在这个例子中看到错误显示std::__cxx11::string Test<BeMyFriend>::mything' is private within this context areyoumyfriend.mything; depicts the status of violation access to a private value, this is because the member function is not befriended to the host class simply. 描述了对私有值的违规访问的状态,这是因为成员函数不能简单地与主机类成为友好关系。

I think the C++ standard prohibits what you are trying to do. 我认为C ++标准禁止你尝试做什么。 Maybe it's a defect/oversight; 也许这是一个缺陷/疏忽; maybe it was intentional. 也许这是故意的。 I'm not sure, so I'll just lay out the pieces I found in the standard (it's safe to skim over the section numbers unless/until someone is checking my analysis) : 我不确定,所以我只会列出我在标准中找到的部分(除非/直到有人检查我的分析,否则可以安全地浏览部分编号)

  1. In 6.4.3.1.2, there is a description of when something is considered to name a constructor. 在6.4.3.1.2中,描述了何时将某些内容命名为构造函数。 This involves the "injected-class-name" which (according to 12.2) means the name of the class inserted into the class' scope. 这涉及“inject-class-name”,它(根据12.2)表示插入类范围的类的名称。 In your context, I read these sections as saying that to name the constructor, you need T:: followed by the class-name of T . 在你的情况下,我阅读这些章节的话说,命名构造函数,则需要T::后跟的类名 T You have T::T , which works if T is considered the class-name of T . 你有T::T ,如果T被认为是T类名T Let's see how this plays out. 让我们看看这是如何发挥作用的。

  2. In 15.1.1, it is stated that your friend declaration would need to name a constructor. 在15.1.1中,声明你的friend声明需要命名一个构造函数。 It goes on to say that the class-name shall not be a typedef-name . 接着说, 类名不应该是typedef-name So we should be fine as long as T is not a typedef-name . 所以只要T不是typedef-name我们就应该没问题。

  3. In 17.1.3, it is stated that in your class Test , the identifier T is a typedef-name . 在17.1.3中,声明在您的class Test ,标识符Ttypedef-name Uh-oh. 嗯,哦。

So it's kind of weird. 所以这有点奇怪。 If I'm reading things correctly, you would need to use friend T::BeMyFriend to name the constructor, which of course only works in this one particular example. 如果我正确地阅读了东西,你需要使用friend T::BeMyFriend来命名构造函数,这当然只适用于这个特定的例子。 For other template parameters, this would look for a member function named "BeMyFriend". 对于其他模板参数,这将查找名为“BeMyFriend”的成员函数。 Not what you are looking for. 不是你想要的。

(You might notice that in the examples of constructors declared as friends, the class name being used is always the name used when defining the class. In that situation, there is no typedef'ing going on, so this issue does not arise.) (您可能会注意到,在声明为friend的构造函数的示例中,正在使用的类名始终是定义类时使用的名称。在这种情况下,没有typedef正在进行,因此不会出现此问题。)

Solution? 解? I think you need to make the class T a friend, make a static function in T a friend and call that from the constructor, or find a (better?) way to do what you want to do without using friends. 我认为你需要使课堂T的朋友,做一个静态函数在T的朋友,并呼吁从构造函数,或者找到一个(更好?)的方式去做你不想使用的朋友做什么。 There is a warning flag waving in the back of my mind when I see a template parameter made a friend -- it's legal, but often goes against the principles of encapsulation. 当我看到一个模板参数成为朋友时,我脑海中挥舞着警告旗帜 - 这是合法的,但往往违背封装原则。

Constructors are very special methods. 构造函数是非常特殊的方法。 They have no return type (not even void) and no real name. 他们没有返回类型(甚至无效),也没有真实姓名。 AFAIK that just cannot be used in friend declaration. AFAIK,不能用于朋友声明。

A possible workaround is to build a copy factory function in class BeMyFriend : 一种可能的解决方法是在BeMyFriend类中构建一个复制工厂函数:

class BeMyFriend
{
public:
 BeMyFriend& operator=(const BeMyFriend& rhs) = default;
 BeMyFriend(const BeMyFriend& rhs) = default;
 static BeMyFriend makeCopy(const BeMyFriend& rhs) {
    BeMyFriend tmp(rhs);
    return tmp;
 }
};

template<class T>
class Test
{
 friend T& T::operator=(const T&); //Works fine, no error
 //friend T::T(const T&); //error: prototype for 'BeMyFriend::BeMyFriend(const BeMyFriend&)' does not match any in class 'BeMyFriend'
 friend T T::makeCopy(const T&);
};

int main()
{
 Test<BeMyFriend> hmm;

 return 0;
}

This does not really answer your question because a default copy construction would not be friend, but in the followin code: 这并没有真正回答你的问题,因为默认的复制结构不是朋友,而是在下面的代码中:

BeMyFriend foo;
BeMyFriend bar = BeMyFriend::makeCopy(foo);

you get a friend copy contruction inside makeCopy , and next one is likely to be elided. 你在makeCopy里面得到了一个朋友的复制makeCopy ,下一个可能会被删除。

Anyway I cannot really imagine a real use case for friending only a specific constructor from a class and not the whode class... 无论如何,我无法真正想象一个真正的用例,只为一个类中的特定构造函数而不是whode类。

I was able to get it to compile in GCC by adding void after friend : 通过在friend之后添加void ,我能够在GCC中编译它:

friend void T::T(const T&);

I was then able to access one of Test 's private members from BeMyFriend 's constructor. 然后,我可以从BeMyFriend的构造函数访问Test的一个私有成员。 However, note that this is compiler specific. 但请注意,这是特定于编译器的。 I tried it in clang, and it did not work. 我试图在铛,并没有奏效。

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

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