18

重複の可能性:
c++0x の再帰ラムダ関数

次のように記述した場合、ラムダを再帰的に呼び出すことができないのはなぜですか。

auto a = [&]
{ 
   static int i = 0; i++;
   std::cout << i << std::endl; 
   if (i<10) 
     a(); //recursive call
};

コンパイル エラー ( ideone )が発生します。

prog.cpp:8:18: error: '((const main()::<lambda()>*)this)->main()::<lambda()>::a' cannot be used as a function

prog.cpp: In function 'int main()':
prog.cpp:9:9: error: variable 'auto a' with 'auto' type used in its own initializer

エラーの意味は何ですか?

これを書けない理由が分かりました:

auto i=i+1; //error: unable to deduce 'auto' from '<expression error>'

iの型は初期化から推測する必要があるiため、これを書くことはできません。しかし、ラムダの場合、それはどのように重要なのでしょうか? 私が間違っていなければ、ラムダの型はそのパラメーターと戻り値の型によって決まります。何も返さない場合は本体に依存しません (この場合、voidラムダ本体の他のステートメントに関係なく、戻り値の型は と推定されます)。

とにかく、回避策があり、std::function代わりに次のように使用できます。

std::function<void()> a = [&] 
{ 
   static int i = 0; i++;
   std::cout << i << std::endl; 
   if (i<10) 
      a();
};

罰金をコンパイルします(ideone)。autoしかし、バージョンがコンパイルされない理由を知りたいと思っています。

4

3 に答える 3

15

その理由は、auto変数のラムダ式初期化子には特別なケースがないためです。

このような特殊なケースでは、エラーや誤用が発生しやすくなります。のようなものが機能することを提案するときは、ルールを定義する必要がありますa()operator()見上げはどうですか?aの型の正確な状態は何ですか? 型はコンプリートでしょうか?(これは、ラムダのキャプチャ リストを既に知っていることを意味します)。仕様に適した形式でそれを定式化すると、それについてのステートメントを作成するのが簡単になります.

ユースケースを許可することは、コードを先にスキャンする必要があるさらに別のケースを意味します。これは、ainの型を決定するには、型をa()「ラムダ解除」できるもので初期化子が終了していないことを確認する必要があるためです。

struct y { void operator()() { } };
template<typename T> y operator+(T, y) { return y(); }
auto x = [] { x(); } + y();

この場合、ラムダではなくx()を呼び出します。y::operator()

現在のようaに、イニシャライザ全体で言及することは単に禁止されています。C++ では、は型でautoないためです。これは、推定される型を表す単なる型指定子です。結果として、式はauto型を持つことはできません。

于 2011-10-22T18:04:17.810 に答える
6

auto a私が見ているように、ケースとケースの重要な違いはstd::function<void()> a、型std::function<void()>が参照する実際の関数の型が実際に何であるかを知らない/気にしないということです。書き込み:

std::function<void()> a;

次のように、完全に問題ありません。

auto a;

ほとんど意味がありません。したがって、キャプチャを合成するときが来たらstd::function<void()>、タイプについて知る必要があるすべてを使用する場合、タイプはすでに知られていますが、autoそれはまだ知られていません。

于 2011-10-22T18:15:53.483 に答える
2

再帰関数fでは によって定義されf、戻り値の型fも によって決定されるfためauto、無限再帰につながります。

auto型を派生させようとするとき。decltype(f()) は、 f が f に派生するので、別の decltype(f)` にさらに推論します。たとえば、再帰的なものに対する呼び出しも再帰的です。戻り値の型の決定は、再帰関数に適用されると再帰的になります。再帰関数では、再帰の終了は実行時に行われる場合があります。しかし、決定は静的のみです

于 2011-10-22T18:22:49.187 に答える