web-dev-qa-db-ja.com

可変長の汎用ラムダを作成するには?

C++ 14以降では、汎用ラムダを使用できます。

auto generic_lambda = [] (auto param) {};

これは基本的に、その呼び出し演算子がautoとしてマークされたパラメーターに基づいてテンプレート化されることを意味します。

問題は、可変個の関数テンプレートがどのように機能するかと同様に、可変個のパラメーターを受け入れることができるラムダを作成する方法です。これが不可能な場合、同じ方法で使用できる最も近いものは何ですか?どのように保管しますか? std::function

36
Drax

構文

可変長の汎用ラムダをどのように作成しますか?

次の構文を使用して、可変個の汎用ラムダを作成できます。

auto variadic_generic_lambda = [] (auto... param) {};

基本的には、auto(おそらく修飾されたref)とパラメーターパック名の間に...を追加するだけです。

したがって、通常、ユニバーサル参照を使用すると次のようになります。

auto variadic_generic_lambda = [] (auto&&... param) {};

使用法

パラメータの使用方法は?

そのため、可変引数ジェネリックパラメーターはテンプレートパラメーターパックタイプを持つと見なす必要があります。これは多かれ少なかれ、それらのパラメーターのすべての使用ではないにしてもほとんどの場合、テンプレートを何らかの方法で必要とすることを意味しています。

典型的な例を次に示します。

#include <iostream>

void print(void)
{
}

template <typename First, typename ...Rest>
void print(const First& first, Rest&&... Args)
{
  std::cout << first << std::endl;
  print(Args...);
}

int     main(void)
{
  auto variadic_generic_lambda = [] (auto... param)
    {
      print(param...);
    };

  variadic_generic_lambda(42, "lol", 4.3);
}

ストレージ

可変長の汎用ラムダをどのように保存しますか?

autoを使用して独自の型の変数にラムダを格納するか、または std::function に格納できますが、呼び出すことしかできません。そのstd::functionに与えた固定署名を使用して:

auto variadic_generic_lambda = [] (auto... param) {};

std::function<void(int, int)> func = variadic_generic_lambda;

func(42, 42); // Compiles

func("lol"); // Doesn't compile

可変個の汎用ラムダのコレクションはどうですか?

すべてのラムダは異なる型を持っているため、直接型をSTLの通常の同種のコンテナに格納することはできません。非ジェネリックラムダで行われる方法は、対応するstd::functionに保存することです。これは、固定のシグネチャ呼び出しを持ち、ラムダはそもそもジェネリックではなく、呼び出すことしかできないため、何も制限しません。そのように:

auto non_generic_lambda_1 = [] (int, char) {};
auto non_generic_lambda_2 = [] (int, char) {};

std::vector<std::function<void(int, char)>> vec;

vec.Push_back(non_generic_lambda_1);
vec.Push_back(non_generic_lambda_2);

このstorageセクションの最初の部分で説明したように、特定の固定呼び出しシグネチャに制限できる場合は、可変長の汎用ラムダでも同じことができます。

できない場合は、次のような何らかの異種コンテナが必要になります。

  • std::vector<boost::variant>
  • std::vector<boost::any>
  • boost::fusion::vector

異種コンテナの例については、 この質問 を参照してください。

ほかに何か ?

ラムダに関するより一般的な情報、生成されるメンバーの詳細、およびラムダ内でのパラメーターの使用方法については、以下を参照してください。

30
Drax

あなたの意図がわからないが、代わりにstd::functionラムダ自体を使用して、パラメータをキャプチャできます。これは、ブーストメーリングリストで説明されている例です。 boost :: hana 実装で使用されます

auto list = [](auto ...xs) {
    return [=](auto access) { return access(xs...); };
};

auto head = [](auto xs) {
    return xs([](auto first, auto ...rest) { return first; });
};

auto tail = [](auto xs) {
    return xs([](auto first, auto ...rest) { return list(rest...); });
};

auto length = [](auto xs) {
    return xs([](auto ...z) { return sizeof...(z); });
};

// etc...
// then use it like

auto three = length(list(1, '2', "3")); 
40
mkaes

このことを考慮

#include <iostream>

    namespace {

        auto out_ = [] ( const auto & val_) 
        {
            std::cout << val_;
            return out_ ;
        };

        auto print = [](auto first_param, auto... params)
        {
            out_(first_param);

            // if there are  more params
            if constexpr (sizeof...(params) > 0) {
                // recurse
                print(params...);
            }
                return print;
        };
    }

int main()
{
    print("Hello ")("from ")("GCC ")(__VERSION__)(" !"); 
}

wandbox here )この「印刷」ラムダは次のとおりです。

  • 可変長
  • 再帰的
  • ジェネリック
  • 速い

また、テンプレートが見えません。 (すぐ下:))ラジオノイズのように見えるC++コードはありません。シンプルでクリーン、そして最も重要なこと:

  • メンテナンスが簡単

「新しい言語のように感じる」のも不思議ではありません。

2
user5560811