[英]How do I define an out-of-line class template member function with a non-trailing decltype return type
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链接 ]
问题是f1
这两个声明是否声明了相同的函数(从技术上讲,同一个类模板的成员函数相同)。 这由[basic.link] / 9管理,根据其中:
两个相同的名称(第6条)和在不同范围内声明的名称应表示相同的变量,函数,类型,模板或名称空间
- 两个名称都有外部链接,否则两个名称都有内部联系,并在同一个翻译单元中声明; 和
- 两个名称都指向同一名称空间的成员或同一类的成员,而不是继承。 和
- 当两个名称都表示函数时,函数的参数类型列表(11.3.5)是相同的; 和
- 当两个名称都表示功能模板时,签名(17.5.6.1)是相同的。
只要返回类型实际上是相同的(因为返回类型是类成员函数模板的签名的一部分,根据[defns.signature.member.templ]),似乎满足要求。 由于foo<T>::x
是int
,它们是相同的。
如果x
的类型是依赖的,则不会出现这种情况。 例如,当x
的声明更改为typename identity<T>::type x;
时,GCC和Clang都拒绝该定义typename identity<T>::type x;
。 [ Coliru link ]在这种情况下,[temp.type] / 2适用:
如果表达式e是类型依赖的(17.6.2.2),则
decltype(
e)
表示唯一的依赖类型。 只有当它们的表达式 s是等价的(17.5.6.1)时,两个这样的decltype-specifiers才引用相同的类型。 [ 注意:但是,这种类型可能是别名,例如,通过typedef-name 。 - 结束说明 ]
也许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链接 ]
(我作弊......有点)
使用MSVC我点击了该成员函数的“快速操作 - >创建函数声明”并获得了:
template<class T>
decltype(x) foo<T>::f1()
{
return x;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.