C++ 使用变量捕获的多回调结构的习惯用法
我有一个函数,它接受一个对象并调用它上的各种回调函数作为它的输出。例如:C++ 使用变量捕获的多回调结构的习惯用法,c++,callback,inversion-of-control,C++,Callback,Inversion Of Control,我有一个函数,它接受一个对象并调用它上的各种回调函数作为它的输出。例如: template<typename T> void iterateInParallel(vector<int> const& a, vector<int> const& b, T && visitor) { // sometimes invokes visitor.fromA(i) // sometimes invokes visitor.
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)
}
这比旧的函子方法要好得多,在函子方法中,我定义了一个类,它在构造函数中引用了sum
和numElems
。和functor方法一样,它通常具有零运行时成本,因为回调代码在实例化函数时是已知的
但是lambda只是一个函数,因此对于上面的iterateInParallel
方法来说是不可行的;我又开始复制参考文献了
因此,我要寻找的是一种方法,可以大致获得lambdas默认捕获的便利性、性能和惯用性,同时仍然能够调用多种类型的回调
我考虑过的选择:
- 传递多个回调函数。这还不算太糟,通常我都是这么做的。但是,很容易混淆参数顺序,而且它实际上会使参数列表膨胀。由于回调的名称不在用户代码中,因此它也不太需要自我记录
- 重写内部函数,使其调用一个回调,并使用参数帮助定义回调的类型。丑陋的,骇人的,不是一个值得尊敬的程序员会做的那种事情
- 传递一个包含一大堆
s的结构。我觉得我可以让它看起来很好,但我也觉得它最终会执行堆分配和每次调用间接寻址std::function
- 涉及预处理器的一些古怪的事情。天哪
#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"; }
});
}
#包括
样板
结构访问者
{
F1来自a;
F2 fromB;
};
样板
访客(F1、F2)->访客;
样板
f(访客五)
{
v、 fromA(1);
v、 fromB(“你好”);
}
int main()
{
f(访客){
.fromA=[](int n){std::cout这还不错,但需要一个尚未完成的标准修订版。此外,这似乎阻止了f
使用“正常”函子。并且缺少限制F1
/F2
;-)的概念@Jarod42你可以在这里传递这个习语;)但是可以。@Sneftel:F1
/F2
可以是常规的函子。如果你在f
中使用std::invoke
而不是operator()
,你甚至可以传递方法上的指针:-)@Jarod42对不起,我应该说“一个普通的结构”与中一样,f
不再是完全参数化的,但需要一个作为visitor
实例的访问者。
#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"; }
});
}