Подтвердить что ты не робот

Как создать вариативную общую лямбду?

Так как С++ 14 мы можем использовать общие lambdas:

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

Это в основном означает, что его оператор вызова шаблонизирован на основе параметров, отмеченных как авто.

Вопрос заключается в том, как создать лямбду, которая может принимать вариационное число параметров аналогично тому, как будет работать шаблон вариационной функции? Если это невозможно, то какая ближайшая вещь может быть использована одинаково? Как бы вы его сохранили? Возможно ли это в std::function?

4b9b3361

Ответ 1

Синтаксис

Как вы создаете вариационную общую лямбду?

Вы можете создать вариативную общую лямбда со следующим синтаксисом:

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

В принципе, вы просто добавляете ... между auto (возможно, квалифицированным) и именем пакета параметров.

Таким образом, типичное использование универсальных ссылок даст:

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);

Как объясняется в первой части этого раздела хранения, если вы можете сдерживать себя определенной фиксированной сигнатурой вызова, вы можете сделать то же самое с вариативными генерируемыми лямбдами.

Если вы не можете, вам понадобится какой-то разнородный контейнер, например:

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

См. этот вопрос для примера гетерогенного контейнера.

Что еще?

Для получения более общей информации о lambdas и подробностей о сгенерированных членах и о том, как использовать параметры в лямбда, см. ниже:

Ответ 2

Я не уверен, каково ваше намерение, но вместо того, чтобы хранить его в 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"));