![](/img/trans.png)
[英]How do I make this template specialization with variadic arguments a friend of a class?
[英]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 type
和prototype 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 ++標准禁止你嘗試做什么。 也許這是一個缺陷/疏忽; 也許這是故意的。 我不確定,所以我只會列出我在標准中找到的部分(除非/直到有人檢查我的分析,否則可以安全地瀏覽部分編號) :
在6.4.3.1.2中,描述了何時將某些內容命名為構造函數。 這涉及“inject-class-name”,它(根據12.2)表示插入類范圍的類的名稱。 在你的情況下,我閱讀這些章節的話說,命名構造函數,則需要T::
后跟的類名 T
。 你有T::T
,如果T
被認為是T
的類名 , T
。 讓我們看看這是如何發揮作用的。
在15.1.1中,聲明你的friend
聲明需要命名一個構造函數。 接着說, 類名不應該是typedef-name 。 所以只要T
不是typedef-name我們就應該沒問題。
在17.1.3中,聲明在您的class Test
,標識符T
是typedef-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.