Ответ 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 и подробностей о сгенерированных членах и о том, как использовать параметры в лямбда, см. ниже: