我最近发现,当用作返回类型时,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(): …Run Code Online (Sandbox Code Playgroud) 这有效并输出“1”,因为函数的约束是部分排序的并且最受约束的重载获胜:
template<class T>
struct B {
int f() requires std::same_as<T, int> {
return 0;
}
int f() requires (std::same_as<T, int> && !std::same_as<T, char>) {
return 1;
}
};
int main() {
std::cout << B<int>{}.f();
}
Run Code Online (Sandbox Code Playgroud)
这也有效,因为显式实例化不会实例化不满足约束的成员函数:
template<class T>
struct B {
int f() requires std::same_as<T, int> {
return 0;
}
int f() requires (!std::same_as<T, int>) {
return 1;
}
};
template struct B<int>;
Run Code Online (Sandbox Code Playgroud)
那么这个应该怎么办呢?
template<class T>
struct B {
int f() requires std::same_as<T, int> {
return …Run Code Online (Sandbox Code Playgroud) c++ language-lawyer explicit-instantiation c++-concepts c++20