Mar*_*asi 7 c++ language-lawyer
template <class T>
struct foo {
int x;
decltype(x) f1();
};
Run Code Online (Sandbox Code Playgroud)
似乎不可能定义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() {}
Run Code Online (Sandbox Code Playgroud)
这不是在实际代码中的问题,因为改变的一流声明f1
,以auto f1() -> decltype(x);
使第二个定义.但我很困惑为什么会改变什么呢.甚至可以宣布原始f1
的外线?
尽管这看起来很愚蠢,但我相信以下内容是正确的:
\n\ntemplate <class T>\nstruct foo {\n int x;\n decltype(x) f1();\n};\n\ntemplate <class T>\nint foo<T>::f1() { return 0; }\n
Run Code Online (Sandbox Code Playgroud)\n\nClang 接受它,但 GCC 不接受,所以我要说我认为 GCC 有一个 bug。[科利鲁链接]
\n\n问题在于这两个声明是否f1
声明相同的函数(更技术地说,是同一个类模板的相同成员函数)。这是由 [basic.link]/9 管辖,根据该规定:
\n\n\n相同的(第 6 条)并且在不同作用域中声明的两个名称应表示相同的变量、函数、类型、模板或命名空间,如果
\n\n\n
\n- 两个名称都具有外部链接,或者两个名称都具有内部链接并且在同一翻译单元中声明;和
\n- 两个名称都引用同一名称空间的成员或同一类的非继承成员;和
\n- 当两个名称都表示函数时,函数的参数类型列表(11.3.5)相同;和
\n- 当两个名称都表示函数模板时,签名 (17.5.6.1) 相同。
\n
如果返回类型实际上相同(因为根据 [defns.signature.member.templ],返回类型是类成员函数模板的签名的一部分),则似乎满足了要求。因为foo<T>::x
是int
,所以它们是相同的。
如果 的类型是相关的,则情况不会如此x
。例如,当 的声明x
更改为时,GCC 和 Clang 都会拒绝该定义typename identity<T>::type x;
。[ Coliru link ] 在这种情况下, [temp.type]/2 将适用:
\n\n\n如果表达式e是类型相关的 (17.6.2.2),
\ndecltype(
则 e)
表示唯一的相关类型。仅当两个这样的 decltype-specifiers 的表达式相等时才引用相同的类型(17.5.6.1)。[注意:但是,这样的类型可以是别名,例如通过typedef-name。\xe2\x80\x94尾注]
也许 GCC 认为x
依赖于类型是错误的(它不应该是)。但是,本说明建议了一种解决方法:
template <class T>\nstruct foo {\n int x;\n decltype(x) f1();\n using x_type = decltype(x);\n};\n\ntemplate <class T>\ntypename foo<T>::x_type foo<T>::f1() { return 0; }\n
Run Code Online (Sandbox Code Playgroud)\n\n这适用于 GCC 和 Clang。[科利鲁链接]
\n 归档时间: |
|
查看次数: |
112 次 |
最近记录: |