1

このスニペットが失敗する理由を理解しようとしています:

#include <iostream>

using namespace std;


template <typename Lambda>
struct Handler
{
  bool _isCompleted;

  bool isCompleted() { return _isCompleted; }

  Lambda _l;
  Handler(Lambda&& l) : _l(l) {}

  void call() { _l(this); }
};

int main()
{
  auto l1 = new Handler( [&](decltype(l1) obj )->
{
  obj->_isCompleted = true;
  cout << " is completed?" << obj->isCompleted() << endl;
});
  l1->call();
};

g++ 4.5 は次のエラーで失敗します。

test.cpp: In function ‘int main()’:
test.cpp:21:17: error: expected type-specifier before ‘Handler’
test.cpp:21:17: error: expected ‘,’ or ‘;’ before ‘Handler’
test.cpp:25:2: error: expected primary-expression before ‘)’ token
test.cpp:25:2: error: expected ‘;’ before ‘)’ token
test.cpp:26:7: error: request for member ‘call’ in ‘* l1’, which is of non-class type ‘int’

私の理解では、それauto l1はに解決されHandler<lambdaType>*、 lambdaType には public function signature が必要void( Handler<LambdaType>*)です。上記の例には明らかな間違いはありません (ラムダとハンドラー型の間の醜さとわずかに病理学的な循環依存関係を除けば)

4

2 に答える 2

5

1つの問題は、@Catが言ったように、テンプレート引数の推定がコンストラクター呼び出しに対して機能しないことです。テンプレート引数は常に指定する必要があります。

もう 1 つの問題は、次のスニペットを使用して Clang によってうまく説明されています。

struct X{
  X(...){}
};

int main(){
  auto l = X([](decltype(l)& o){});
}

出力:

t.cpp:6:26: error: variable 'l' declared with 'auto' type cannot appear in its
      own initializer
  auto l = X([](decltype(l)& o){});
                         ^
1 error generated.

必須の標準見積もり:

§7.1.6.4 [dcl.spec.auto] p3

それ以外の場合、変数の型は初期化子から推定されます。宣言されている変数の名前は、初期化式には現れません。[...]

于 2012-05-21T17:42:18.110 に答える
2

型推論はコンストラクターでは機能しません。autoはい、式の型を推測しますが、new Handler()明示的な型が必要です。代わりにファクトリー関数を書きます:

// also don't use raw owning pointers
template <typename L>
std::unique_ptr<Handler<L>> make_handler(L lambda) {
    return std::unique_ptr<Handler<L>>(new Handler<L>(lambda));
}

確かに、それは自分自身を少し繰り返していますが、一度だけです. それからあなたはすることができます

auto l1 = make_handler([](...) { ... });
auto l2 = make_handler([](...) { ... });

そしてそれはうまくいくでしょう。

于 2012-05-21T17:36:06.960 に答える