decltype(auto)有哪些用途?

时间:2014-06-08 19:00:32

标签: c++ auto c++14 decltype return-type-deduction

在c ++ 14中引入了decltype(auto)成语。

通常,允许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)];
}

这个新语言功能是否有用?

2 个答案:

答案 0 :(得分:129)

通用代码中的返回类型转发

对于非通用代码,如您提供的初始示例,您可以手动选择将引用作为返回类型:

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)...); 
}

在递归模板中延迟返回类型推导

在几天前的this Q&A中,当模板的返回类型指定为decltype(iter(Int<i-1>{}))而不是decltype(auto)时,遇到模板实例化期间的无限递归。

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]

  

1 autodecltype(auto)类型指定者指定一个占位符   将在以后替换的类型,可以通过从中扣除   初始化程序或通过具有尾随返回类型的显式指定。   auto类型指定符也用于表示lambda是a   通用lambda。

     

2占位符类型可以在decl-specifier-seq,type-specifier-seq中使用函数声明符出现,   convert-function-id或trailing-return-type,在此类声明者有效的任何上下文中。如果功能   declarator包含一个trailing-return-type(8.3.5),它指定函数的声明返回类型。   如果函数的声明返回类型包含占位符类型,则函数的返回类型为   从函数体中的return语句推导出来,如果有的话。

草案还包含变量初始化的这个例子:

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)

答案 1 :(得分:26)

here引用内容:

  • decltype(auto)主要用于推断转发函数和类似包装器的返回类型,您希望类型完全“跟踪”您正在调用的某个表达式。

  • 例如,鉴于以下功能:


   string  lookup1();
   string& lookup2();

  • 在C ++ 11中,我们可以编写以下包装函数,这些函数会记住保留返回类型的引用:

   string  look_up_a_string_1() { return lookup1(); }
   string& look_up_a_string_2() { return lookup2(); }

  • 在C ++ 14中,我们可以自动化:

   decltype(auto) look_up_a_string_1() { return lookup1(); }
   decltype(auto) look_up_a_string_2() { return lookup2(); }

  • 但是,decltype(auto)并不是一个广泛使用的功能。

  • 特别是,虽然它可以用于声明局部变量,但这样做可能只是一个反模式,因为局部变量的引用不应该依赖于初始化表达式。

  • 此外,它对您编写return语句的方式很敏感。

  • 例如,以下两个函数具有不同的返回类型:


   decltype(auto) look_up_a_string_1() { auto str = lookup1(); return str; }
   decltype(auto) look_up_a_string_2() { auto str = lookup2(); return(str); }

  • 第一个返回string,第二个返回string&,这是对局部变量str的引用。

proposal您可以看到更多预期用途。