C++ decltype(auto) 有哪些用途?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/24109737/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 00:38:18  来源:igfitidea点击:

What are some uses of decltype(auto)?

c++autoc++14decltypereturn-type-deduction

提问by Nikos Athanasiou

In c++14 the decltype(auto)idiom is introduced.

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

Typically its use is to allow autodeclarations to use the decltyperules on the given expression.

通常它的用途是允许auto声明使用decltype给定表达式的规则

Searching for examples of "good" usage of the idiom I can only think of things like the following (by Scott Meyers), namely for a function's return type deduction:

搜索该习语的“良好”用法示例时,我只能想到以下内容(由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)];
}

Are there any other examples where this new language feature is useful?

是否有其他示例说明此新语言功能很有用?

回答by TemplateRex

Return type forwarding in generic code

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

For non-generic code, like the initial example you gave, you can manually select to get a reference as a return type:

对于非通用代码,就像您给出的初始示例一样,您可以手动选择以获取引用作为返回类型:

auto const& Example(int const& i) 
{ 
    return i; 
}

but in generic codeyou want to be able to perfectly forward a return typewithout knowing whether you are dealing with a reference or a value. decltype(auto)gives you that ability:

但是在通用代码中,您希望能够完美地转发返回类型,而无需知道您是在处理引用还是值。decltype(auto)给你这种能力:

template<class Fun, class... Args>
decltype(auto) Example(Fun fun, Args&&... args) 
{ 
    return fun(std::forward<Args>(args)...); 
}

Delaying return type deduction in recursive templates

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

In this Q&Aa few days ago, an infinite recursion during template instantiation was encountered when the return type of the template was specified as decltype(iter(Int<i-1>{}))instead of decltype(auto).

这个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)is used here to delay the return type deductionafter the dust of template instantiation has settled.

decltype(auto)用于在模板实例化尘埃落定后延迟返回类型推导

Other uses

其他用途

You can also use decltype(auto)in other contexts, e.g. the draft Standard N3936also states

您也可以decltype(auto)在其他上下文中使用,例如标准草案N3936也指出

7.1.6.4 auto speci?er [dcl.spec.auto]

7.1.6.4 自动指定器 [dcl.spec.auto]

1 The autoand decltype(auto)type-speci?ers designate a placeholder type that will be replaced later, either by deduction from an initializer or by explicit speci?cation with a trailing-return-type. The autotype-speci?er is also used to signify that a lambda is a generic lambda.

2 The placeholder type can appearwith a function declarator in the decl-specifier-seq, type-specifier-seq, conversion-function-id, or trailing-return-type, in any context where such a declarator is valid. If the function declarator includes a trailing-return-type (8.3.5), that specifies the declared return type of the function. If the declared return type of the function contains a placeholder type, the return type of the function is deduced from return statements in the body of the function, if any.

1autodecltype(auto)类型说明符指定稍后将被替换的占位符类型,通过从初始值设定项推导或通过带有尾随返回类型的显式说明进行替换。该auto类型SPECI?呃也用于表示一个lambda是一个通用的λ。

2 占位符类型可以在 decl-specifier-seq、type-specifier-seq、conversion-function-id 或 trailing-return-type与函数声明符一起出现在此类声明有效的任何上下文中。如果函数声明符包含尾随返回类型 (8.3.5),则指定函数声明的返回类型。如果函数声明的返回类型包含占位符类型,则从函数体中的 return 语句(如果有)推导出函数的返回类型。

The draft also contains this example of variable initialization:

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

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)

回答by 101010

Quoting stuff from here:

引用这里的东西:

  • decltype(auto)is primarily useful for deducing the return type of forwarding functions and similar wrappers, where you want the type to exactly “track” some expression you're invoking.

  • For example, given the functions below:

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

  • 例如,给定以下函数:



   string  lookup1();
   string& lookup2();


  • In C++11 we could write the following wrapper functions which remember to preserve the reference-ness of the return type:
  • 在 C++11 中,我们可以编写以下包装函数,它们记住保留返回类型的引用性:


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


  • In C++14, we can automate that:
  • 在 C++14 中,我们可以自动化:


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


  • However, decltype(auto)is not intended to be a widely used feature beyond that.

  • In particular, although it can be used to declare local variables, doing that is probably just an antipattern since a local variable's reference-ness should not depend on the initialization expression.

  • Also, it is sensitive to how you write the return statement.

  • For example, the two functions below have different return types:

  • 但是,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); }


  • The first returns string, the second returns string&, which is a reference to the local variable str.
  • 第一个返回string,第二个返回string&,它是对局部变量的引用str

From the proposalyou can see more intended uses.

提案中您可以看到更多的预期用途。