[英]How to avoid redefinition error in case of in-class definition of friend function template?
[英]Friend template function in-class definition
我不知道,為什么gcc編譯這段代碼
#include <type_traits>
template<class Type, class ValueT>
class ImplAdd
{
template<typename T>
friend typename std::enable_if<std::is_same<T, ValueT>::value, Type>::type
operator+(T, T)
{
return Type{};
}
};
enum class FooValueT { ONE, ZERO };
class Foo : ImplAdd<Foo, FooValueT>
{
public:
Foo() {}
Foo(FooValueT) {}
};
struct A {};
int main()
{
Foo f = FooValueT::ONE + FooValueT::ZERO;
}
clang和msvc不編譯,在我看來,他們是對的。 它是GCC編譯器中的錯誤嗎? gcc的版本是4.8.2。
問題是由我的問題答案造成的: 課堂上的朋友操作員似乎沒有參與重載解析 ,有標准答案引用,指出,這樣的定義應該在類范圍內,如果函數不是模板 - gcc拒絕這段代碼,這是對的。 感謝您的答案,以及標准的引用,證明gcc是對(或不對)非常感謝。
我會說GCC接受這個錯誤。 引用C ++ 11,強調我的:
命名空間成員資格,7.3.1.2 / 3
首先在名稱空間中聲明的每個名稱都是該名稱空間的成員。 如果非本地類中的
friend
聲明首先聲明一個類或函數,那么友元類或函數是最內層封閉命名空間的成員。 在非命名查找(3.4.1)或限定查找(3.4.3)之前找不到朋友的名稱,直到在該命名空間范圍內提供匹配聲明(在授予友誼的類定義之前或之后)。 如果調用了友元函數,則可以通過名稱查找找到其名稱,該名稱查找考慮名稱空間中的函數和與函數參數類型相關聯的類(3.4.2)。 ...
參數依賴查找,3.4.2 / 2:
對於函數調用中的每個參數類型
T
,存在一組零個或多個關聯的命名空間以及要考慮的一組零個或多個關聯的類。 命名空間和類的集合完全由函數參數的類型(以及任何模板模板參數的命名空間)決定。 用於指定類型的Typedef名稱和using-declarations對此集合沒有貢獻。 命名空間和類的集合按以下方式確定:
- ...
- 如果
T
是枚舉類型,則其關聯的命名空間是定義它的命名空間。 如果是類成員,則其關聯類是成員的類; 否則它沒有關聯的類。- ...
3.4.2 / 4:
在考慮關聯的命名空間時,查找與關聯命名空間用作限定符時執行的查找相同(3.4.3.2),但以下情況除外:
- ...
- 在關聯類中聲明的任何命名空間范圍的朋友函數或友元函數模板在其各自的命名空間中都是可見的,即使它們在普通查找期間不可見(11.3)。
- ...
基於以上所述,我認為FooValueT
( FooValueT::ONE
和FooValueT::TWO
)具有::
作為關聯的命名空間,但沒有關聯的類(因為它是枚舉)。 因此,在ADL期間不應考慮在類模板ImplAdd
定義的友元函數。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.