c++ - 模板 lambda 与带有模板运算符()的仿函数
问题描述
受这个问题的启发,我想将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 捕获负责捕获所需的变量。
除了简单之外,上述两种方法之间还有其他具体区别吗?效率怎么样?
解决方案
我在第二个示例中看到的主要缺点是,为了模拟 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);
我看到仿函数的主要缺点(我认为这是一个缺点值得怀疑)是您不能简单地通过引用或值([&]
或[=]
)捕获所有外部变量,但您必须明确列出您使用的所有变量,在定义函子和初始化函子对象时。
题外话:注意我已经在我的结构中标记const
了。operator()
nal
如果您不修改捕获的变量,则 lambda 等效于带有 constant 的函子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
推荐阅读
- javascript - 移动设备上的 HTML 布局无法正常工作
- python - 在 Pandas 中将数值转换为分类
- c - 有没有办法提取作为给定 c 代码中的参数传递给特定函数的变量?
- pdf - 如何将带有我不关心的图像的 PDF 转换为文本?
- python - 如何在 re.search Python 中忽略返回 None
- bash - Bash 在两个字符串之间打印文件内容
- dns - 更改名称服务器后 Bigrock 子域无法正常工作
- javascript - 如何使用 window.open 将在 HTML 中创建的窗口调整为显示器的全宽并限制高度
- webforms - 在 Web 表单中使用 Autofac MultiTenancy 时出现 500.19 错误
- reactjs - 从嵌套类组件更改 React Context 中的值