簡體   English   中英

如何使模板參數的構造函數成為朋友?

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

在C ++ 11中,他們可以簡單地與friend T模板參數。 您還可以使用friend T::Method()在該參數中使用friend T::Method()

但是,你如何與模板參數的構造函數相關聯?

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;
}

我能夠模板參數的operator=很好,但我不能交朋友T::T(const T&)

我怎樣才能成為friend T::T(const T&); 工作?


編輯:這似乎與Make Friend在模板類的構造函數中解決的問題不同。 那里的問題是在聲明中處理循環模板參數。 它不處理實際模板參數的構造函數。

Foo的類型是普通的模板化類,而不是像我的例子中的T這樣的模板參數。 像那個提交的friend Foo<B>::Foo<B>()這樣的東西應該編譯得很好,不像我和friend T::T(const T&)這里的問題。

編輯:如果這最終成為問題,我正在使用gcc 7.2進行編譯。

編輯:我還想澄清一下,C ++確實支持讓構造函數成為朋友。 例如, friend X::X(char), X::~X(); http://en.cppreference.com/w/cpp/language/friend的第一個例子中。

這里的問題是如何使模板參數的構造函數成為朋友。

不知怎的,我認為編譯器沒有很好地解析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&::這足以消除歧義。

你可以在這里檢查實例化器是否“完美地工作”並且值正確地結合了。

如果,無論如何,你在這個例子中看到錯誤顯示std::__cxx11::string Test<BeMyFriend>::mything' is private within this context areyoumyfriend.mything; 描述了對私有值的違規訪問的狀態,這是因為成員函數不能簡單地與主機類成為友好關系。

我認為C ++標准禁止你嘗試做什么。 也許這是一個缺陷/疏忽; 也許這是故意的。 我不確定,所以我只會列出我在標准中找到的部分(除非/直到有人檢查我的分析,否則可以安全地瀏覽部分編號)

  1. 在6.4.3.1.2中,描述了何時將某些內容命名為構造函數。 這涉及“inject-class-name”,它(根據12.2)表示插入類范圍的類的名稱。 在你的情況下,我閱讀這些章節的話說,命名構造函數,則需要T::后跟的類名 T 你有T::T ,如果T被認為是T類名T 讓我們看看這是如何發揮作用的。

  2. 在15.1.1中,聲明你的friend聲明需要命名一個構造函數。 接着說, 類名不應該是typedef-name 所以只要T不是typedef-name我們就應該沒問題。

  3. 在17.1.3中,聲明在您的class Test ,標識符Ttypedef-name 嗯,哦。

所以這有點奇怪。 如果我正確地閱讀了東西,你需要使用friend T::BeMyFriend來命名構造函數,這當然只適用於這個特定的例子。 對於其他模板參數,這將查找名為“BeMyFriend”的成員函數。 不是你想要的。

(您可能會注意到,在聲明為friend的構造函數的示例中,正在使用的類名始終是定義類時使用的名稱。在這種情況下,沒有typedef正在進行,因此不會出現此問題。)

解? 我認為你需要使課堂T的朋友,做一個靜態函數在T的朋友,並呼吁從構造函數,或者找到一個(更好?)的方式去做你不想使用的朋友做什么。 當我看到一個模板參數成為朋友時,我腦海中揮舞着警告旗幟 - 這是合法的,但往往違背封裝原則。

構造函數是非常特殊的方法。 他們沒有返回類型(甚至無效),也沒有真實姓名。 AFAIK,不能用於朋友聲明。

一種可能的解決方法是在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;
}

這並沒有真正回答你的問題,因為默認的復制結構不是朋友,而是在下面的代碼中:

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

你在makeCopy里面得到了一個朋友的復制makeCopy ,下一個可能會被刪除。

無論如何,我無法真正想象一個真正的用例,只為一個類中的特定構造函數而不是whode類。

通過在friend之后添加void ,我能夠在GCC中編譯它:

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

然后,我可以從BeMyFriend的構造函數訪問Test的一個私有成員。 但請注意,這是特定於編譯器的。 我試圖在鐺,並沒有奏效。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM