1

次の模範的な関数があると仮定します。

template <typename Fn> auto call(Fn fn) -> decltype(fn()) {
  return fn();
}

この関数の重要な点は、その戻りタイプが、推測できるテンプレートパラメーターに依存することです。したがって、最終的には、戻り型は関数の呼び出し方法によって異なります。

現在、テストクラスもあります。

struct X {
  int u;
  auto test() -> decltype(call([this]() -> double {this->u = 5; return 7.4;})) {
    return call([this]() -> double {this->u = 5; return 7.4;});
  }
};

ご覧のとおり、をX::test呼び出しcallて、同じ戻り値を返します。この場合、リターンタイプは自明にとして与えられますdoubleが、少しの間、何が行われるのかわからずcall、ラムダがより複雑なリターンタイプを持っていると仮定しましょう。

これをコンパイルしようとすると、コンパイラは文句を言います。これはthis、トップレベルで使用しているためです(式を許可するスコープではありません)。

error: lambda-expression in unevaluated context
error: invalid use of ‘this’ at top level

ただし、の戻り型を正しく取得するには、渡すラムダのキャプチャを使用する必要があります。ラムダを残したまま、これを回避する方法を提案しますか?callcall

注:もちろん、ラムダをoperator()何らかのヘルパータイプに移動することもできます。これは、thisポインターのコピーを使用してインスタンス化しますが、その定型文は避けたいと思います。

4

3 に答える 3

2

気になる本当のエラーは「未評価のコンテキストでのラムダ式」だと思います。すべてのラムダ式には一意の型があるため、未評価のコンテキストでラムダを使用することはできません。つまり、許可された場合、他のコンテキストdecltype([]{})とは異なるタイプを推測します。[]{}つまりdecltype([]{}) fn = []{};、動作しません。

リターンタイプを推測するのではなく、明示的に記述したい場合を除いて、必要なコンテキストで使用できる実際のタイプを作成する以外に選択肢はないと思います。

メンバー関数ではないように変更testすることが許容される場合でも、本体が単一のreturnステートメントである場合は、ラムダがreturn型を省略して、戻り型を推測できるという事実を使用できます。

template <typename Fn> auto call(Fn fn) -> decltype(fn()) {
    return fn();
}

struct X {
    int u;
};

int main() {
    auto test = [](X *x) { return call([x]() -> double {x->u = 5; return 7.4; });};

    X x;
    test(&x);
}

関数の末尾の戻り型の構文に同じプロパティがあると便利です。なぜそうならないのかわかりません。

于 2012-05-11T13:53:21.727 に答える
0

それは、(解釈された、人工的な)構成された質問のようです。

  • 他の場所からラムダを取得する場合は、名前が付けられており、バインドに問題はありませんthis

  • 他の場所からラムダを取得していない場合は、結果のタイプがわかります。

要するに、問題は現在述べられているので(私がこの答えを書いているように)、あなた自身の意志によって課されたものを除いて問題はありません。

しかし、それを主張する場合はthis、ラムダ定義を介してバインドするのではなく、引数として渡すだけです。次に、を呼び出すためcallに、引数をバインドします。しかし、言うまでもなく、それは作り上げられた問題を解決するだけなので、それは本物のルーブ・ゴールドバーグの構造であり、それ自体の複雑さの外では何も解決しない、花が咲き乱れる不必要な複雑さにまともです。

もしあれば、元の本当の問題は何でしたか?

于 2012-05-11T13:16:29.720 に答える
0

関数本体を常にコピーアンドペーストする必要はありませんdecltype。遅く指定された戻り型を導入するポイントは、引数から正しい戻り型を何らかの方法で推測できるようになることでした。
auto f(T x) -> decltype(g(x)) { return h(), g(x); }-> decltype(h(), g(x))

したがって、あなたの場合は、の動作を知っており、それに渡すラムダ関数の戻り型を知ってdouble test()いるので、十分です。 より複雑なケースでは、に関する知識やその他のものを使用して、内部のコードを減らす必要があります。call
decltypecall

于 2012-05-11T13:42:59.953 に答える