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
不合格?
答案 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>::x
为int
,因此它们是相同的。
如果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>