Jak stworzyć zmienną generyczną lambdę?
Od C++14 możemy używać ogólnych lambdów:
auto generic_lambda = [] (auto param) {};
Oznacza to, że operator wywołania jest wzorowany na parametrach oznaczonych jako auto.
Pytanie brzmi, jak stworzyć lambda, która może przyjmować zmienną liczbę parametrów, podobnie jak będzie działał zmienny szablon funkcji ? Jeśli nie jest to możliwe, jaka jest najbliższa rzecz, która może być używana w ten sam sposób ?
Jak byś to przechowywał ? Czy jest to możliwe w std::function
?
3 answers
Nie jestem pewien, jaki jest Twój zamiar, ale zamiast przechowywać go w std::function
możesz użyć samej lambdy, aby uchwycić params.
Jest to przykład omawiany na liście dyskusyjnej boost. Jest używany w implementacji 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"));
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-09-20 09:36:09
Składnia
Jak stworzyć zmienną lambdę generyczną ?
Możesz utworzyć zmienną generyczną lambda o następującej składni:
auto variadic_generic_lambda = [] (auto... param) {};
W zasadzie wystarczy dodać ...
pomiędzy auto
(ewentualnie ref) a nazwą Twojego parametru.
Więc typowo używając uniwersalnych odniesień dałoby:
auto variadic_generic_lambda = [] (auto&&... param) {};
Użycie
Jak korzystać z parametrów ?
Należy wziąć pod uwagę zmienny parametr ogólny jako posiadanie parametru szablonu typu pack, ponieważ tak jest. To mniej więcej oznacza, że większość, jeśli nie wszystkie, użycie tych parametrów będzie wymagało szablonów w ten czy inny sposób.
Oto typowy przykład:
#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);
}
Przechowywanie
Jak przechowywać zmienną generyczną lambdę ?
Możesz użyć auto
do przechowywania lambda w zmiennej własnego typu, lub możesz zapisać ją w std::function
ale będziesz mógł zadzwonić tylko z poprawiony podpis pod tym 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
A co z kolekcjami różnych rodzajów lambda ?
Ponieważ każda lambda ma inny typ, nie można przechowywać ich bezpośredniego typu w zwykłych jednorodnych pojemnikach stl. Sposób, w jaki robi się to z innymi rodzajowymi lambdami, polega na przechowywaniu ich w odpowiedniej std::function
, która będzie miała stałe wywołanie sygnatury i nie będzie niczego powstrzymywać, ponieważ twoja lambda nie jest generyczna w pierwszej kolejności i może być wywołany w ten sposób:
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);
Jak wyjaśniono w pierwszej części tej sekcji storage jeśli możesz ograniczyć się do danej stałej sygnatury wywołania, możesz zrobić to samo z zmienną generyczną lambda.
Jeśli nie możesz, będziesz potrzebował jakiejś formy heterogenicznego kontenera, takiej jak:
std::vector<boost::variant>
std::vector<boost::any>
boost::fusion::vector
Zobacz to pytanie dla przykładu heterogenicznego pojemnika.
Co jeszcze ?
Aby dowiedzieć się więcej na temat lambda oraz szczegółów na temat generowanych prętów i jak korzystać z parametrów w lambda, zobacz: [19]}Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:46:24
Rozważ to
#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 tutaj ) to "Drukuj" lambda to:
- Variadic
- rekurencyjne
- ogólne
- Fast
I żadnych szablonów w zasięgu wzroku. (tuż pod spodem:)) Brak kodu C++ wyglądającego jak szum radiowy. Proste, czyste i co najważniejsze:
- Łatwy w utrzymaniu
Nic dziwnego ,że "czuje się jak nowy język".