受this question的启发,我想将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;
}
在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捕获负责捕获所需的变量。
除了简单之外,上述两种方法之间是否还有其他具体区别?效率如何?
答案 0 :(得分:2)
在第二个示例中看到的主要缺点是,要模拟lambda捕获,需要将所有局部变量(在本例中为ina a)显式传递给函子。
我不同意。
您几乎可以看到带有一个operator()
和一些与捕获的变量相对应的成员的lambda类/结构。
所以不是
[&]<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);
我对函子看到的主要缺点(并且我认为这是一个缺点是可疑的)是您不能简单地通过引用或值([&]
或[=]
)捕获所有外部变量,但您必须显式列出您使用的所有变量,包括定义函子和初始化函子对象。
主题外:观察到我在const
结构中标记了operator()
nal
。
如果不修改捕获的变量,则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
,则会出现编译错误