Ber*_*nor 8 c++ gcc c++11 c++14
我最近发现,当用作返回类型时,decltype表达式作为函数符号名称的一部分被破坏,并且这可能是导致令人讨厌的分段错误,同时解析表达式(例如在调试会话中),如果表达式是太复杂了.
第一个版本,在函数返回类型中使用decltype,其中完整表达式被破坏(http://goo.gl/EALubx):
#include <cstdint>
#include <utility>
struct A { void bar() const; };
template<typename T>
decltype(std::declval<T>().bar()) foo(T const& a);
void foo() { A a; return foo(a); }
Run Code Online (Sandbox Code Playgroud)
编译为(GCC 5.2.0):
foo():
sub rsp, 24
lea rdi, [rsp+15]
call decltype ((((declval<A>)()).bar)()) foo<A>(A const&)
add rsp, 24
ret
Run Code Online (Sandbox Code Playgroud)
第二个版本,几乎等效,其中表达式类型作为附加模板参数的一部分被解析(http://goo.gl/DfQGR5):
#include <cstdint>
#include <utility>
struct A { void bar() const; };
template<typename T, typename R=decltype(std::declval<T>().bar())>
R foo(T const& a);
void foo() { A a; return foo(a); }
Run Code Online (Sandbox Code Playgroud)
编译为(GCC 5.2.0):
foo():
sub rsp, 24
lea rdi, [rsp+15]
call void foo<A, void>(A const&)
add rsp, 24
ret
Run Code Online (Sandbox Code Playgroud)
我知道模板函数只能在它们的返回类型上重载,但是编译器不应该能够自己解析decltype表达式而是破坏结果类型吗?
任何人都可以告诉我为什么,或者指出我在C++规范中指定的位置?
回答:
正如TC在评论中所解释的,原因在于模板函数重载规则[temp.over.link]/5-6
例如:
// #1
template<typename T>
decltype(std::declval<T>().bar()) foo(T const& a);
// #2 same function as #1, because both are "equivalent":
// declared in the same scope, with the same name and
// argument/return type expressions are "equivalent"
template<typename U>
decltype(std::declval<U>().bar()) foo(U const& a);
// #3 overloads #1, because argument/return type expressions
// may not be resolved to the same value for any given set of T
template<typename T>
decltype(std::declval<T>().baz()) foo(T const& a);
Run Code Online (Sandbox Code Playgroud)
这也意味着以下内容是格式错误的:
// #1
template<typename T>
decltype(std::declval<T>().bar(2)) foo(T const& a);
// #2 is "functionally equivalent" but not "equivalent" to #1
// because argument/return type expressions are not "equivalent"
// but "functionally equivalent": they are resolved to the same value
// for any given T
template<typename T>
decltype(std::declval<T>().bar(1+1)) foo(T const& a);
Run Code Online (Sandbox Code Playgroud)