2012-05-11 17 views
1

は、私は以下の例示的な機能を持っていると仮定しますdecltype式で変数を指定する方法を教えてください。

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 

しかし、私が持っているcallの返品タイプを取得するためにcallに渡すラムダのキャプチャを使用する。ラムダを残しながら、これを回避するにはどうしたらいいですか?

注:ラムダをのヘルパータイプにすることもできますが、これはthisポインタのコピーでインスタンス化しますが、定型文を避けたいと思います。

+0

少なくともgcc 4.5に準拠したいです。 – bitmask

+0

ラムダ式を例えば'decltype'(これは最初のエラーが何を意味しているか)であるので、別の問題もあります。 –

+0

@LucDanton:ありがとう。私はそれを認識しませんでした。あなたはこの質問の延長を考えますか?私は新しいものを開くべきですか?それを回避する機会はありますか? – bitmask

答えて

2

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

戻り値の型を推定するのではなく、明示的に書きたい場合を除き、必要なコンテキストで使用できる実数型を作成する以外に選択肢はありません。 。メンバ関数ではないとtestを変更すると、あなたが体は、単一の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); 
} 

それは、関数の末尾の戻り値の型構文が同じプロパティを持っていればいいでしょう。私はなぜそれがしないのか分からない。

0

それが命名しても問題はthisを結合しないです、あなたはどこか別の場所からラムダを取得する場合

  • 以来、作ら(解釈、人工的な)問題のようです。

  • ラムダを他の場所から取得していない場合は、結果の型がわかります。 (私はこの答えを書いていたように)問題は、現在記載されているよう要するに

は、あなた自身の意志によって課されるものを除いて全く問題ありません。

しかし、あなたが主張しているのであれば、ラムダ定義でバインドする代わりに、thisを引数として渡すだけです。次にcallへの呼び出しのために、引数をバインドします。しかし、おそらく言うまでもなく、それはメークアップ問題を解決するだけなので、実際のルーベ・ゴールドバーグの建設であり、過剰な花開きの不必要な複雑さはまったく複雑ではありません。

本物の問題があればそれは何ですか?

+0

問題は解決されません。たぶん私はあなたの明白な解決策(それは皮肉ではない、私はしばしば明らかに見落とす)を見て失敗します。 'call'の定義を見ることなく、' X :: test'の戻り値の型は何ですか? – bitmask

+0

@bitmask:それを使用するには 'call'のdefを知る必要があります。それを使用するためにラムダを知る必要があります。問題が解決した場合、この場合の戻り値の型は 'double'です。本当に未知の 'call'を使う必要があれば、' decltype'の呼び出しにダミーラムダ(実際のものと同じ戻り値の型)を渡すだけです。繰り返しますが、問題は解決しました。なぜなら、あなたはコールサイト*で必要な知識をすべて持っているからです。 –

+0

申し訳ありませんが、Lucが主な質問に対するコメントで正しいとすれば、あなたは 'decltype'の中にラムダを置くことはできません。知りませんでした。しかし、それを確認してください! –

0

ファンクション本体は、必ずdecltypeにコピー&ペーストしないでください。遅れて指定された戻り値型を導入する点は、引数から正しい戻り値の型を何らかの形で推測できるということでした。
は、ない-> decltype(h(), g(x))

だから、あなたの場合には、double test()は、私たちがcallの行動を知っていると我々はラムダ関数の戻り値の型を知っているので、我々はそれに渡す、十分です。
さらに複雑なケースでは、decltypeのコードをcallなどの知識を使用して減らす必要があります。

関連する問題