web-dev-qa-db-ja.com

decltype(auto)の用途は何ですか?

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

この新しい言語機能が役立つ他の例はありますか?

128

ジェネリックコードでの戻り型転送

最初の例のように、非汎用コードの場合、戻り値の型として参照を取得するように手動で選択できます。

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 autoおよびdecltype(auto)型指定子は、初期化子からの演orまたは末尾復帰型での明示的な指定のいずれかによって、後で置換されるプレースホルダー型を指定します。 auto型指定子は、ラムダが汎用ラムダであることを示すためにも使用されます。

2プレースホルダータイプ表示可能は、decl-specifier-seq、type-specifier-seq、conversion-function-id、またはtrailing-return-typeに関数宣言子がありますin anyそのような宣言子が有効なコンテキスト。関数宣言子に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)
142
TemplateRex

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ステートメントの記述方法にも影響を受けます。

  • たとえば、次の2つの関数には異なる戻り型があります。


   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を返し、2番目はstring&を返します。これはローカル変数strへの参照です。

proposal から、より多くの用途がわかります。

26
101010