template <class T> struct foo { int x; decltype(x) f1(); };
似乎不可能将f1定义为脱节.我尝试了以下定义,但它们都不起作用:
template <class T> decltype(x) foo<T>::f1() {} template <class T> auto foo<T>::f1() -> decltype(x) {} template <class T> auto foo<T>::f1() { return x; } template <class T> decltype(std::declval<foo<T>>().x) foo<T>::f1() {} // This return type is copied from the gcc error message template <class T> decltype (((foo<T>*)(void)0)->foo<T>::x) foo<T>::f1() {}
这在实际代码中不是问题,因为将f1的类内声明更改为auto f1() – > decltype(X);允许第二个定义.但我很困惑为什么会改变什么呢.是否有可能将原始f1声明为脱离线?
解决方法
template <class T> struct foo { int x; decltype(x) f1(); }; template <class T> int foo<T>::f1() { return 0; }
Clang接受了它,但是GCC没有,所以我要说我认为GCC有一个bug. [Coliru link]
问题是f1的这两个声明是否声明了相同的函数(从技术上讲,同一个类模板的成员函数相同).这由[basic.link] / 9管理,根据其中:
Two names that are the same (Clause 6) and that are declared in different scopes shall denote the same variable,function,type,template or namespace if
- both names have external linkage or else both names have internal linkage and are declared in the same translation unit; and
- both names refer to members of the same namespace or to members,not by inheritance,of the same class; and
- when both names denote functions,the parameter-type-lists of the functions (11.3.5) are identical; and
- when both names denote function templates,the signatures (17.5.6.1) are the same.
只要返回类型实际上是相同的(因为返回类型是类成员函数模板的签名的一部分,根据[defns.signature.member.templ]),似乎满足要求.由于foo< T> :: x是int,它们是相同的.
如果x的类型是依赖的,则不会是这种情况.例如,当x的声明更改为typename identity< T> :: type x;时,GCC和Clang都拒绝该定义. [Coliru link]在这种情况下,[temp.type] / 2将适用:
If an expression e is type-dependent (17.6.2.2),
decltype(
e)
denotes a unique dependent type. Two such
decltype-specifiers refer to the same type only if their expressions are equivalent (17.5.6.1). [ Note: However,such a type may be aliased,e.g.,by a typedef-name. — end note ]
也许GCC错误地认为x是依赖于类型的(它不应该是).但是,本说明提出了一种解决方法:
template <class T> struct foo { int x; decltype(x) f1(); using x_type = decltype(x); }; template <class T> typename foo<T>::x_type foo<T>::f1() { return 0; }
这适用于GCC和Clang. [Coliru link]