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)];
}
この新しい言語機能が役立つ他の例はありますか?
最初の例のように、非汎用コードの場合、戻り値の型として参照を取得するように手動で選択できます。
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)
here :からの引用
decltype(auto)
は主に転送関数と同様のラッパーの戻り値の型を推測するのに役立ちます。あなたが呼び出しています。
たとえば、次の関数を考えます:
string lookup1();
string& lookup2();
string look_up_a_string_1() { return lookup1(); }
string& look_up_a_string_2() { return lookup2(); }
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 から、より多くの用途がわかります。