在 c++14decltype(auto)中引入了这个成语。
decltype(auto)
通常它的用途是 允许auto声明使用decltype给定表达式的规则。
auto
decltype
搜索成语“良好”用法的示例,我只能想到以下内容(由Scott Meyers 撰写),即 函数的返回类型推导 :
template<typename ContainerType, typename IndexType> // C++14 decltype(auto) grab(ContainerType&& container, IndexType&& index) { authenticateUser(); return std::forward<ContainerType>(container)[std::forward<IndexType>(index)]; }
是否有任何其他示例表明此新语言功能很有用?
对于非泛型代码,就像您给出的初始示例一样,您可以手动选择以获取引用作为返回类型:
auto const& Example(int const& i) { return i; }
但是在 通用代码 中,您希望能够 完美地转发返回类型 ,而无需知道您是在处理引用还是值。decltype(auto)给你这样的能力:
template<class Fun, class... Args> decltype(auto) Example(Fun fun, Args&&... args) { return fun(std::forward<Args>(args)...); }
在前几天的这个问答中,当模板的返回类型被指定为decltype(iter(Int<i-1>{}))而不是decltype(auto).
decltype(iter(Int<i-1>{}))
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(auto)此处用于 延迟 模板实例化尘埃落定后的返回类型推导。
您也可以decltype(auto)在其他情况下使用,例如标准草案 N3936 还指出
7.1.6.4 汽车规范 [dcl.spec.auto]
1auto和decltype(auto)类型说明符指定稍后将被替换的占位符类型,或者通过从初始化程序中推导,或者通过带有尾随返回类型的显式说明符。type- speci铿乪autor 也用于表示 lambda 是通用 lambda。 2 占位符类型 可以 与 decl-specifier-seq、type-specifier-seq、conversion-function- id 或 trailing-return-type 中的函数声明符一起出现, 在此类声明符有效的任何上下文中 。如果函数声明符包含一个 trailing-return-type (8.3.5),它指定了函数声明的返回类型。如果函数声明的返回类型包含占位符类型,则函数的返回类型是从函数体中的返回语句推导出来的,如果有的话。
1auto和decltype(auto)类型说明符指定稍后将被替换的占位符类型,或者通过从初始化程序中推导,或者通过带有尾随返回类型的显式说明符。type- speci铿乪autor 也用于表示 lambda 是通用 lambda。
2 占位符类型 可以 与 decl-specifier-seq、type-specifier-seq、conversion-function- id 或 trailing-return-type 中的函数声明符一起出现, 在此类声明符有效的任何上下文中 。如果函数声明符包含一个 trailing-return-type (8.3.5),它指定了函数声明的返回类型。如果函数声明的返回类型包含占位符类型,则函数的返回类型是从函数体中的返回语句推导出来的,如果有的话。
草案还包含这个变量初始化的例子:
int i; int&& f(); auto x3a = i; // decltype(x3a) is int decltype(auto) x3d = i; // decltype(x3d) is int auto x4a = (i); // decltype(x4a) is int decltype(auto) x4d = (i); // decltype(x4d) is int& auto x5a = f(); // decltype(x5a) is int decltype(auto) x5d = f(); // decltype(x5d) is int&& auto x6a = { 1, 2 }; // decltype(x6a) is std::initializer_list<int> decltype(auto) x6d = { 1, 2 }; // error, { 1, 2 } is not an expression auto *x7a = &i; // decltype(x7a) is int* decltype(auto)*x7d = &i; // error, declared type is not plain decltype(auto)