Вдохновленный этим вопросом , я бы хотел сравнить использование c++20
шаблона лямбда с функтором, имеющим шаблон operator()
.
. В качестве контрольного примера рассмотримшаблонная функция call
, которая принимает лямбда-шаблон в качестве аргумента и вызывает эту лямбду, создавая его экземпляр с некоторыми параметрами шаблона.Следующий код c++20
иллюстрирует идею.
#include <tuple>
#include <utility>
template <int I, class Lambda, class... ArgsType>
void call(Lambda&& F, ArgsType&& ...args)
{
F.template operator()<I>(std::forward<ArgsType>(args)...);
}
int main() {
std::tuple<int, double, int> t{0,0,0};
int a = 2;
auto f = [&]<int I>(auto& x) { std::get<I>(x) += I + a; };
call<0>(f, t);
return 0;
}
В c++11
/ c++14
/ c++17
без лямбды-шаблона та же задача может быть реализована с помощью функтора, имеющего шаблонoperator()
, как в следующем коде.
#include <tuple>
#include <utility>
template <int I, class Lambda, class... ArgsType>
void call(Lambda&& F, ArgsType&& ...args)
{
F.template operator()<I>(std::forward<ArgsType>(args)...);
}
struct Functor {
template <int I, class T>
void operator()(const int& a, T& x) { std::get<I>(x) += I + a; };
};
int main() {
std::tuple<int, double, int> t{0,0,0};
int a = 2;
Functor func{};
call<0>(func, a, t);
}
Основной недостаток, который я вижу во втором примере, заключается в том, что для эмуляции лямбда-захвата необходимо явно передавать все локальные переменные (в данном случае int a
) функтору.Это может быть утомительно, если Functor::operator()
нужно много переменных от своего "владельца".В конце концов, можно также передать указатель this
на Functor::operator()
.Таких осложнений нет в примере c++20
, где лямбда-захват заботится о захвате необходимых переменных.
Помимо простоты, есть ли какое-либо другое конкретное различие между двумя подходами, описанными выше?А как насчет эффективности?