繁体   English   中英

带有模板operator()的模板lambda vs functor

[英]template lambda vs functor with template operator()

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

作为一个测试用例,考虑一个模板函数call ,该函数以模板lambda作为参数,并调用该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;
}

在没有模板lambda的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);

}

在第二个示例中,我看到的主要缺点是,为了模拟lambda捕获,需要将所有局部变量(在本例中为int a )显式传递给函子。 如果Functor::operator()需要其“所有者”中的许多变量,这可能很乏味。 最终,一个也可能是通过指针thisFunctor::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()

如果您不修改捕获的变量,则lambda等效于具有常量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则会出现编译错误

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM