模板lambda vs foundor带有模板操作员()

template lambda vs functor with template operator()

本文关键字:操作员 lambda vs foundor 模板      更新时间:2023-10-16

受这个问题的启发,我想将c++20模板lambda与具有模板operator()的函数进行比较。

作为测试用例,请考虑将模板lambda作为参数的模板函数call,并将此lambda称为使用某些模板参数对其进行实例化。以下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中,没有模板lambda,可以使用函数,具有模板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);
}

我在第二个示例中看到的主要缺点是,要模拟lambda捕获,需要将所有局部变量(在这种情况下为 int a(明确传递给函数。如果Functor::operator()需要其"所有者"的许多变量,这可能很乏味。最终,也许也可以将指针this传递给Functor::operator()c++20中没有这种并发症,其中lambda捕获会照顾捕获所需的变量。

除了简单之外,上面概述的两种方法之间还有其他具体差异吗?效率呢?

我在第二个示例中看到的主要缺点是,要模仿lambda捕获,需要明确将所有局部变量(在本例中为int a(转移到函数。

我不同意。

您几乎可以将lambda视为具有operator()的类/结构,而某些对应于捕获变量的成员。

所以而不是

[&]<int I>(auto& x) { std::get<I>(x) += I + a; };

您可以写(已经来自C 11(

struct nal // not a lambda
 {
   int const & a;
   template <int I, typename T>
   auto operator() (T & x) const
    { std::get<I>(x) += I + a; }
 };

并按照以下方式使用它

call<0>(nal{a}, t);

我在函数上看到的主要缺点(我想这是一个不利的问题(是,您不能简单地通过参考或值捕获([&][=](,所有外部变量,但您必须明确列出您使用的所有变量,包括定义函子和初始化函数对象。

主题:观察我已经在我的nal结构中标记了const operator()

如果您不修改捕获的变量,则lambdas等于具有常数operator()的函子。

如果您将函数作为常量参考

传递,这很重要
template <int I, class Lambda, class... ArgsType>
void call (Lambda const & F, ArgsType&& ...args)
{ // ......^^^^^^^^^^^^^^  now F is a constant reference
  F.template operator()<I>(std::forward<ArgsType>(args)...); // compilation error
                                                             // if operator()
                                                             // isn't const
} 

如果operator()不是const

,您会遇到汇编错误