繁体   English   中英

如何使用非尾随decltype返回类型定义外联类模板成员函数

[英]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>::xint ,它们是相同的。

如果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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM