web-dev-qa-db-ja.com

ラムダ関数でautoを使用する

#include <vector>
#include <algorithm>

void foo( int )
{
}

int main()
{
  std::vector< int > v( { 1,2,3 } );

  std::for_each( v.begin(), v.end(), []( auto it ) { foo( it+5 ); } );
}

コンパイルすると、上記の例は次のようにエラー出力を開始します。

h4.cpp: In function 'int main()':
h4.cpp:13:47: error: parameter declared 'auto'
h4.cpp: In lambda function:
h4.cpp:13:59: error: 'it' was not declared in this scope

キーワードautoをラムダ式で使用しないでください。

これは動作します:

std::for_each( v.begin(), v.end(), []( int it ) { foo( it+5 ); } );

Autoキーワードを含むバージョンが機能しないのはなぜですか?

39
BЈовић

c ++ 11では、autoキーワードは関数引数の型として機能しません。ラムダ関数で実際の型を使用したくない場合は、以下のコードを使用できます。

 for_each(begin(v), end(v), [](decltype(*begin(v)) it ){
       foo( it + 5);         
 });

問題のコードは、C++ 14では問題なく動作します。

67
Jagannath

C++ 14では、ラムダ関数(ジェネリックラムダ関数)パラメーターをautoで宣言できます。

auto multiply = [](auto a, auto b) {return a*b;};

詳細: http://en.cppreference.com/w/cpp/language/lambda

22
Razan Paul

これは、インタビュー中にHerb Sutterによって簡単に議論されました。 auto引数に対する要求は、実際にはany関数がautoで次のように宣言可能であることを要求することと同じです。

auto add(auto a, auto b) -> decltype(a + b) { return a + b; }

ただし、これは実際には関数ではなく、template関数であり、次のようなものです。

template <typename S, typename T>
auto add(S a, T b) -> decltype(a + b) { return a + b; }

したがって、本質的には、引数を変更することによって任意の関数をテンプレートに変換する機能を求めています。テンプレートはC++の型システムでは非常に異なる種類のエンティティであるため(2フェーズルックアップや演繹など、テンプレートのすべての特別なルールを考えてください)、これは予期せぬ影響を伴う根本的な設計変更となります。 tいつでも規格に入る予定です。

20
Kerrek SB

コンパイラがstd::for_eachをインスタンス化する前に、ラムダのタイプを知っておく必要があります。一方、理論的には可能であるとしても、ファンクターがどのように呼び出されるかを確認することによってfor_eachがインスタンス化された後にのみ、そのautoを推定できます。

可能であれば、for_eachを忘れて、範囲ベースのforループを使用してください。

for (int it : v) { 
   foo(it + 5); 
}

これはauto(およびauto&const auto&)にもうまく対応するはずです。

for (auto it : v) { 
   foo(it + 5); 
}
4
visitor