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

时间:2018-03-19 21:42:39

标签: c++ language-lawyer

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不合格?

2 个答案:

答案 0 :(得分:2)

尽管看起来很愚蠢但我认为以下是正确的:

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管理,根据其中:

  

两个相同的名称(第6条)以及在不同范围内声明的名称,如果

,则表示相同的变量,函数,类型,模板或名称空间。      
      
  • 两个名称都有外部链接,或者两个名称都有内部链接,并在同一个翻译单元中声明;和
  •   
  • 这两个名称指的是同一名称空间的成员或同一类的成员,而不是继承。和
  •   
  • 当两个名称都表示函数时,函数的参数类型列表(11.3.5)是相同的;和
  •   
  • 当两个名称都表示功能模板时,签名(17.5.6.1)是相同的。
  •   

如果返回类型实际上是相同的(因为返回类型是类成员函数模板的签名的一部分,根据[defns.signature.member.templ]),似乎满足要求。由于foo<T>::xint,因此它们是相同的。

如果x的类型依赖,则不会出现这种情况。例如,当x的声明更改为typename identity<T>::type x;时,GCC和Clang都拒绝该定义。 [Coliru link]在这种情况下,[temp.type] / 2适用:

  

如果表达式 e 与类型有关(17.6.2.2),decltype( e )表示唯一的依赖类型。两个这样的    decltype-specifiers 仅当它们的表达式是等效的(17.5.6.1)时才引用相同的类型。 [注意:但是,这样的类型可能是别名,例如,通过 typedef-name 。 - 结束记录]

考虑到x依赖于类型(它不应该是),GCC可能会出错。但是,本说明提出了一种解决方法:

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]

答案 1 :(得分:0)

(我作弊......有点)

使用MSVC我点击了该成员函数的“快速操作 - &gt;创建函数声明”并得到了这个:

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="maindiv">
  <div id="div1">Lorem</div>
  <div id="div2">Ipsum</div>
  <div id="div3">Dolor</div>
  <div id="div4">Sit</div>
  <div id="div5">Amet</div>
</div>