expr
和auto f() -> decltype(auto) { return expr; } // 1
auto f() -> decltype(expr) { return expr; } // 2
作为函数(模板)的返回类型有什么区别,如果f
在两种情况下都没有使用括号?
expr
以上expr
可以在任何上下文中定义/声明,可以是(成员)函数或(成员)函数模板,甚至是(泛型)lambda。 /api/register
可以依赖于任何模板参数。
在第二个版本中,/api/register
只是没有额外括号的完全相同的表达式。
在C ++ 14及更高版本中使用第一种或第二种形式可以预期哪些差异?
如果在任何地方使用括号怎么办?
答案 0 :(得分:14)
是的,有区别。第一个将根据函数体中的返回表达式检测返回类型。
第二个也不会将返回类型设置为decltype()
内的表达式类型,但也会在其上应用表达式sfinae 。这意味着如果decltype中的表达式无效,编译器将搜索另一个有效的重载。而第一个版本将是一个硬错误。
举个例子:
template<typename T>
auto fun(T a) -> decltype(a.f()) { return a.f(); }
template<typename T>
auto fun(T a) -> decltype(a.g()) { return a.g(); }
struct SomeType {
int g() { return 0; }
};
fun(SomeType{});
选择正确的过载。现在,如果我们将decltype(expr)
替换为decltype(auto)
,编译器将无法选择正确的重载,因为函数签名中没有任何限制类型应该是什么能够做到。
答案 1 :(得分:6)
decltype(auto)
用于
在通用代码中转发返回类型,您不想输入大量重复的内容
template<class Func, class... Args>
decltype(auto) foo(Func f, Args&&... args)
{
return f(std::forward<Args>(args)...);
}
延迟类型扣除,正如您在this question中看到的那样,编译器出现问题decltype(auto)
template<int i> struct Int {};
constexpr auto iter(Int<0>) -> Int<0>;
template<int i> constexpr auto iter(Int<i>) -> decltype(iter(Int<i-1>{}));
int main(){
decltype(iter(Int<10>{})) a;
}
这很有效,因为您可以看到here:
template<int i> struct Int {};
constexpr auto iter(Int<0>) -> Int<0>;
template<int i>
constexpr auto iter(Int<i>) -> decltype(auto) {
return iter(Int<i-1>{});
}
int main(){
decltype(iter(Int<10>{})) a;
}
decltype(expr)
:
decltype(auto)
不是