【发布时间】:2016-10-09 16:10:53
【问题描述】:
我想在 C++ 中有一个 dynamic_call 功能。它应该触发重载决议并根据参数的动态类型调用目标类(访问者)上最具体的函数。它应该替换访问者模式,并且应该像 C# 中的动态关键字一样工作。 我把到目前为止我得到的东西贴在下面。我不想在调用方声明通用 lambda,而是在动态调用的实现上声明它以使其更易于使用。这可能吗?
#include <iostream>
struct Base { virtual ~Base() = default; };
class A : public Base {};
class B : public Base {};
template <class... Ts>
class dynamic_call {
public:
template <class F, class Arg>
static void call(F& func, Arg& a) {
call_impl<F, Arg, Ts...>(func, a);
}
private:
template <class F, class Arg>
static void call_impl(F& /*func*/, Arg& /*a*/) {
//end of recursion => nothing more to be done
}
template <class F, class Arg, class T, class... R>
static void call_impl(F& func, Arg& a) {
T* t = dynamic_cast<T*>(&a);
if(t) {
func(*t);
}
call_impl<F, Arg, R...>(func, a);
}
};
using namespace std;
struct Visitor {
void Visit(A&) { cout << "visited for a" << endl; }
void Visit(B&) { cout << "visited for b" << endl; }
};
int main(int /*argc*/, char */*argv*/[])
{
Visitor v;
auto func = [&v](auto& a) { v.Visit(a); };
A a;
dynamic_call<A, B>::call(func, a);
B b;
dynamic_call<A, B>::call(func, b);
{
Base& base(a);
dynamic_call<A, B>::call(func, base);
}
{
Base& base(b);
dynamic_call<A, B>::call(func, base);
}
return 0;
}
我想这样调用它而不需要添加通用 lambda。
dynamic_call<A,B>::call(v, a);
【问题讨论】:
-
使用
std::function可能。你的问题不清楚 -
我是否理解正确,您基本上希望
Visit(或对它的包装调用)表现得像Base的虚拟成员函数?关于您的最后一个要求:将Visitor中的Visit更改为operator(),您的线路将正常工作。 -
@eichhörnchen 不,我想根据参数的运行时类型调用正确的访问实现。这不是普通的虚拟通话。
-
虚拟调用根据
this的运行时类型选择被覆盖的方法,即如果Visit是Base中的虚拟方法并在A和B中被覆盖,没有参数,然后a.Visit()、b.Visit()和base.Visit()的行为与您的 dynamic_call 示例完全相同。 -
是否将
Visit替换为operator(),将func(*t)替换为func.Visit(*t),在Visit内部进行调度,或者将调度调用包装在一个额外的成员函数/结构中没有选项?