3

C++1y は、多態的なラムダを提供します (つまり、autoパラメーター型の一部として使用します)。

int         f(int);
double      f(double);
std::string f(const std::string&);

auto funcObj = [](const auto& param){ return f(param); }

示されているように、ラムダによって生成されたクロージャを格納するのは簡単autoです。変数を使用するだけです。vectorしかし、そのようなオブジェクトのを作成したいとします。つかむタイプはvector?通常の答えは を使用することstd::functionですが、この場合は機能しません。知る限り、ポリモーフィックのようなものがないためですstd::function。つまり、これは C++1y では合法ではありません。

std::vector<std::function<auto(const auto&)>> vecOfPolymorphicClosures;

これが合法である場合、コールバックのコンテナーを作成するなどのことができます。各コンテナーは任意の引数セットで呼び出すことができ、それぞれが渡された引数の型に依存する型を返すことができます。auto少なくとも理論上は、任意のコールバックの結果を変数に格納できます。

2 つの質問:

  • C++1y で、さまざまなタイプのポリモーフィック ラムダ (のようなもの以外boost::any) を保持できる変数またはコンテナーを宣言する方法はありますか?
  • そのようなことが可能になることを期待するのは理にかなっていますか、それともこの種のことは静的型付けと互換性がありませんか?
4

3 に答える 3

3

いいえ、そうかもしれません。

f特定のケースでは、ラムダは、インスタンス化時に既知の単一の関数のオーバーライド セットにすぎません。オーバーライド セット オブジェクトを作成し、型消去を使用して渡すことができますが、ほとんど問題はありません。オーバーライドを手動で列挙し、それをオーバーライド セットに提供するだけです。

したがって、あなたの目標が のオーバーライド セットであるオブジェクトを持つことだけである場合f、はい、これを行うことができます。「手動」署名オーバーロード解決を参照してください-その混乱の上にいくつかのタイプ消去を追加してください。ボブはあなたの叔父です。

autoその中に任意のコードを含むラムダがある一般的なケースでは、いいえ。

この問題を想定する方法は、ラムダでコンパイルされた DLL または共有ライブラリ、functionlike オブジェクトを保持する 2 番目の DLL または共有ライブラリ、およびそれを呼び出したい他の DLL または共有ライブラリを想像することです。

を呼び出したときに発生する動作は、ラムダの定義、任意の程度で呼び出したい型functionに依存します。

これが機能するためには、ほぼ完全なランタイム コンパイル モデルが、ラムダが作成された DLL と、それが呼び出される型の DLL の両方で利用可能である必要があり、そのランタイム コンパイル モデルは、互換性。

これは、C++ 標準では要求されておらず、要求された場合ははるかに複雑になり、最適化の機会が失われます。

さて、すべてが絶望的というわけではありません。

サポートしたいタイプの固定リストがある場合は、ポリモーフィックfunctionシグネチャを記述できます。これは基本的に、上記の「オーバーライド セット」ソリューションの特殊なケースであり、それを使用して記述することもできます。

一方、引数のプロパティをラムダに型消去し、型を消去して、何らかの統一型 (それまたは何でも) を返しboost::anyたいboost::variant場合は、何かを行うことができます。型消去オブジェクト型を作成し、公開します。次にstd::function< boost::any(type_erasure_object) >、 があり、変換は呼び出しの外部で発生し、呼び出し内で、前述のタイプの消去されたオブジェクトを処理します。

型が消去されたオブジェクトを使用してオーバーロードを選択するのは注意が必要です。C++ コンパイラは、考慮すべきオーバーロードのリストを生成するのにあまり役に立ちません。そのリストを手動で収集する場合は、選択するオーバーロードを erase と入力することもできます。

それをやってのけることは可能ですが、私は以前にそれを書いたことがありません. これに代わるものはすべてはるかに簡単です。

特定の種類の最適化をブロックするため、この問題を解決するために type erased ケースを考慮しません。しかし、理論的には、ほぼ任意の型を操作できることを意味します。

型消去オブジェクトはエンド ユーザーに公開する必要があり、すべてのラムダに押し込む必要がある型情報のすべての部分を消去する必要があります。したがって、これにより、場合によっては保存するラムダが大幅に制限される可能性があります。std::vectorstd::vector

ほぼ任意のオブジェクトを消去する方法の例については、boost type erasure を参照してください。

最後に、あなたが求めていることが問題の実際の要件であることはめったにありません。あなたの実際の実際的な問題を説明するのが最善でしょう.ほぼ確実に上記の問題ほど難解ではない解決策があります.

于 2013-10-30T01:18:10.993 に答える
1

いわゆるジェネリック ラムダの型は、メンバー template を持つクラス型operator()です。変換が必要な場合は、実際の型がわかっている必要があります。非キャプチャ汎用ラムダの場合、現在のドラフト標準には例も含まれています。

auto glambda = [](auto a) { return a; };
int (*fp)(int) = glambda;

これは、通常の関数テンプレートから関数ポインタを作成するのと同じです。

一般的な汎用ラムダの場合、呼び出し可能なオブジェクトを期待する変換は正しいテンプレートの特殊化をトリガーするので、std::function<int(int)> f(glambda);うまく機能するはずです。

于 2013-10-29T23:45:21.927 に答える