我有一个函数,它接受一个对象并在其上调用各种回调函数作为其输出。例如:
template<typename T>
void iterateInParallel(vector<int> const& a, vector<int> const& b, T && visitor)
{
// sometimes invokes visitor.fromA(i)
// sometimes invokes visitor.fromB(i)
// sometimes invokes visitor.fromBoth(i, j)
}
(不要完全了解该功能的作用,这是一个例子,在这里不相关。)
现在,在编写代码以使用带回调对象的函数时,我经常会使用带有默认by-ref捕获的本地lambda来保持代码的紧密性和可读性。
int sum = 0;
int numElems = 0;
someFunctionTakingACallback(args, [&](int x) {sum += x; numElems++; });
这比旧的仿函数方法更好很多,我在其中定义了一个类,在其构造函数中将refs引入sum
和numElems
。与仿函数方法一样,它通常没有运行时成本,因为在实例化函数时已知回调代码。
但是lambda只是一个函数,因此它不适用于上面的iterateInParallel
方法;我回来复制refs了。
所以我正在寻找的是一种从lambdas的default-capture获得大致方便性,性能和惯用性的方法,同时仍能调用多种类型的回调。
我考虑的选项:
std::function
s的结构。我觉得我可以看到 okay ,但我也觉得它最终会进行堆分配和每次调用间接。答案 0 :(得分:4)
Deduction guides (C++17)和designated initialization (c++20)一起提供了合适的解决方案:
#include <iostream>
template<class F1, class F2>
struct Visitor
{
F1 fromA;
F2 fromB;
};
template<class F1, class F2>
Visitor(F1, F2) -> Visitor<F1, F2>;
template<class F1, class F2>
void f(Visitor<F1, F2> v)
{
v.fromA(1);
v.fromB("hello");
}
int main()
{
f( Visitor{
.fromA = [](int n){ std::cout << "A: " << n << "\n"; },
.fromB = [](std::string_view v){ std::cout << "B: " << v << "\n"; }
});
}
(demo)