有人能想出一个好方法来使用类似下面的 Object::foo
重载的东西来实现多重分派(dispatch)吗?
class A {
public:
virtual void accept (Visitor&) = 0;
};
class B : public A {
virtual void accept (Visitor&) override;
};
class C : public A {
virtual void accept (Visitor&) override;
};
class D : public A {
virtual void accept (Visitor&) override;
};
class Object {
public:
virtual double foo (A*, A*) { std::cout << "Object::foo A,A\n"; return 3.14; }
virtual double foo (B*, B*) { std::cout << "Object::foo B,B\n"; return 3.14; }
virtual double foo (B*, C*) { std::cout << "Object::foo B,C\n"; return 3.14; }
virtual double foo (C*, B*) { std::cout << "Object::foo C,B\n"; return 3.14; }
virtual double foo (C*, C*) { std::cout << "Object::foo C,C\n"; return 3.14; }
virtual char foo (A*, A*, A*) const { std::cout << "Object::foo A,A,A\n"; return '&'; }
virtual char foo (C*, B*, D*) const { std::cout << "Object::foo C,B,D\n"; return '!'; } // Overload of foo with three arguments.
virtual void bar (A*, A*, A*) const { std::cout << "Object::bar A,A,A\n"; }
virtual void bar (B*, B*, B*) const { std::cout << "Object::bar B,B,B\n"; }
virtual void bar (B*, C*, B*) const { std::cout << "Object::bar B,C,B\n"; }
virtual void bar (B*, C*, C*) const { std::cout << "Object::bar B,C,C\n"; }
virtual void bar (B*, C*, D*) const { std::cout << "Object::bar B,C,D\n"; }
virtual void bar (C*, B*, D*) const { std::cout << "Object::bar C,B,D\n"; }
virtual void bar (C*, C*, C*) const { std::cout << "Object::bar C,C,C\n"; }
virtual void bar (D*, B*, C*) const { std::cout << "Object::bar D,B,C\n"; }
double fooMultipleDispatch (A*, A*);
char fooMultipleDispatch (A*, A*, A*);
void barMultipleDispatch (A*, A*, A*);
template <template <int...> class Z1, template <int...> class Z2, int... Is, int... Js>
double multipleDispatch (const ObjectFooVisitor<2>& visitor, const Z1<Is...>&, const Z2<Js...>&) {return foo (visitor.getArray<Is>()[Js]...);}
template <template <int...> class Z1, template <int...> class Z2, int... Is, int... Js>
char multipleDispatch (const ObjectFooVisitor<3>& visitor, const Z1<Is...>&, const Z2<Js...>&) const {return foo (visitor.getArray<Is>()[Js]...);}
template <template <int...> class Z1, template <int...> class Z2, int... Is, int... Js>
void multipleDispatch (const ObjectBarVisitor& visitor, const Z1<Is...>&, const Z2<Js...>&) {bar (visitor.getArray<Is>()[Js]...);}
};
我用来执行多重分派(dispatch)的客户端代码如下所示:
int main() {
A* a[] = {new B, new C, new D};
Object* object = new Object;
double d = object->foo (a[0], a[1]); // Object::foo A,A (no multiple dispatch)
d = object->fooMultipleDispatch (a[0], a[1]); // Object::foo B,C
std::cout << "d = " << d << std::endl; // 3.12
const char k = object->fooMultipleDispatch (a[1], a[0], a[2]); // Object::foo C,B,D
std::cout << "k = " << k << std::endl; // !
object->bar (a[1], a[0], a[2]); // Object::bar A,A,A (no multiple dispatch)
object->barMultipleDispatch (a[1], a[0], a[2]); // Object::bar C,B,D
Thing* thing = new Thing;
int num = thing->baz (a[1], a[0], a[2]); // Thing::baz A,A,A (no multiple dispatch)
num = thing->bazMultipleDispatch (a[1], a[0], a[2]); // Thing::baz C,B,D
std::cout << "num = " << num << std::endl; // 5
}
您可以从我的设计中推断出我的解决方案在维护类别中惨遭失败。每次一个带有重载的新函数被多重分派(dispatch)时,一个新的对应的访问者类等...(例如,在这种情况下 ObjectFooVisitor
,函数 Object::fooMultipleDispatch
, 等等...) 需要被写入。理想的设计不应需要此类维护工作。
一个示例 Visitor 函数,我只是多次分派(dispatch) Object::foo,如下所示:
template<>
class ObjectFooVisitor<2> : public Visitor { // For Object::foo overrides with two arguments.
private:
std::tuple<std::array<B*, 2>, std::array<C*, 2>> tupleOfArrays;
std::array<int, 2> tupleIndices;
// ....
};
double Object::fooMultipleDispatch (A* a1, A* a2) {
ObjectFooVisitor<2> visitor;
a1->accept(visitor); // Stores the dynamic type of a1
a2->accept(visitor); // and a2 into ObjectFooVisitor<2>'s array data members.
return MultipleDispatcher<Object, ObjectFooVisitor<2>, double, 2, 0, index_sequence<0>>(this, visitor).execute(); // 2 because there are two arguments in the Object::foo overloads.
}
所以我遵循的主要思想是存储动态类型指针数组的元组,然后使用此存储来调用适当的重载。但必须有其他设计才能使它更好地工作。
如果您想查看它,这是我的完整解决方案(在 GCC 4.9.2 上编译,需要 SFINAE 支持)。随意尝试改进它以使其更易于维护,但我确信需要新的设计。
#include <iostream>
#include <array>
#include <tuple>
#include <type_traits>
class Object; class B; class C; class D;
class Visitor {
public:
virtual void visit (B*) = 0;
virtual void visit (C*) = 0;
virtual void visit (D*) = 0;
};
class A {
public:
virtual void accept (Visitor&) = 0;
};
class B : public A {
virtual void accept (Visitor&) override;
};
class C : public A {
virtual void accept (Visitor&) override;
};
class D : public A {
virtual void accept (Visitor&) override;
};
template <int, int> struct ArrayType; // Extra template parameter N needed here to allow std::array of any size.
template <int N> struct ArrayType<N,0> { using type = std::array<B*, N>; };
template <int N> struct ArrayType<N,1> { using type = std::array<C*, N>; };
template <int N> struct ArrayType<N,2> { using type = std::array<D*, N>; };
template <int> class ObjectFooVisitor;
template<>
class ObjectFooVisitor<2> : public Visitor { // For Object::foo overrides with two arguments.
private:
std::tuple<std::array<B*, 2>, std::array<C*, 2>> tupleOfArrays;
std::array<int, 2> tupleIndices;
int numAccepted = 0;
protected:
virtual void visit (B* b) override {std::get<0>(tupleOfArrays)[numAccepted] = b; tupleIndices[numAccepted++] = 0;}
virtual void visit (C* c) override {std::get<1>(tupleOfArrays)[numAccepted] = c; tupleIndices[numAccepted++] = 1;}
virtual void visit (D*) override {}
public:
ObjectFooVisitor() { std::get<0>(tupleOfArrays) = {{nullptr, nullptr}}; std::get<1>(tupleOfArrays) = {{nullptr, nullptr}}; }
template <int N> const typename ArrayType<2,N>::type& getArray() const {return std::get<N>(tupleOfArrays);}
const std::array<int, 2>& getTupleIndices() const {return tupleIndices;}
};
template<>
class ObjectFooVisitor<3> : public Visitor { // For Object::foo overrides with three arguments.
private:
std::tuple<std::array<B*, 3>, std::array<C*, 3>, std::array<D*, 3>> tupleOfArrays;
std::array<int, 3> tupleIndices;
int numAccepted = 0;
protected:
virtual void visit (B* b) override {std::get<0>(tupleOfArrays)[numAccepted] = b; tupleIndices[numAccepted++] = 0;}
virtual void visit (C* c) override {std::get<1>(tupleOfArrays)[numAccepted] = c; tupleIndices[numAccepted++] = 1;}
virtual void visit (D* d) override {std::get<2>(tupleOfArrays)[numAccepted] = d; tupleIndices[numAccepted++] = 2;}
public:
ObjectFooVisitor() { std::get<0>(tupleOfArrays) = {{nullptr, nullptr, nullptr}}; std::get<1>(tupleOfArrays) = {{nullptr, nullptr, nullptr}}; std::get<2>(tupleOfArrays) = {{nullptr, nullptr, nullptr}}; }
template <int N> const typename ArrayType<3,N>::type& getArray() const {return std::get<N>(tupleOfArrays);}
const std::array<int, 3>& getTupleIndices() const {return tupleIndices;}
};
class ObjectBarVisitor : public Visitor {
private:
std::tuple<std::array<B*, 3>, std::array<C*, 3>, std::array<D*, 3>> tupleOfArrays;
std::array<int, 3> tupleIndices;
int numAccepted = 0;
protected:
virtual void visit (B* b) override {std::get<0>(tupleOfArrays)[numAccepted] = b; tupleIndices[numAccepted++] = 0;}
virtual void visit (C* c) override {std::get<1>(tupleOfArrays)[numAccepted] = c; tupleIndices[numAccepted++] = 1;}
virtual void visit (D* d) override {std::get<2>(tupleOfArrays)[numAccepted] = d; tupleIndices[numAccepted++] = 2;}
public:
ObjectBarVisitor() { std::get<0>(tupleOfArrays) = {{nullptr, nullptr, nullptr}}; std::get<1>(tupleOfArrays) = {{nullptr, nullptr, nullptr}}; std::get<2>(tupleOfArrays) = {{nullptr, nullptr, nullptr}}; }
template <int N> const typename ArrayType<3,N>::type& getArray() const {return std::get<N>(tupleOfArrays);}
const std::array<int, 3>& getTupleIndices() const {return tupleIndices;}
};
class ThingBazVisitor : public Visitor {
private:
std::tuple<std::array<B*, 3>, std::array<C*, 3>, std::array<D*, 3>> tupleOfArrays;
std::array<int, 3> tupleIndices;
int numAccepted = 0;
protected:
virtual void visit (B* b) override {std::get<0>(tupleOfArrays)[numAccepted] = b; tupleIndices[numAccepted++] = 0;}
virtual void visit (C* c) override {std::get<1>(tupleOfArrays)[numAccepted] = c; tupleIndices[numAccepted++] = 1;}
virtual void visit (D* d) override {std::get<2>(tupleOfArrays)[numAccepted] = d; tupleIndices[numAccepted++] = 2;}
public:
ThingBazVisitor() { std::get<0>(tupleOfArrays) = {{nullptr, nullptr, nullptr}}; std::get<1>(tupleOfArrays) = {{nullptr, nullptr, nullptr}}; std::get<2>(tupleOfArrays) = {{nullptr, nullptr, nullptr}}; }
template <int N> const typename ArrayType<3,N>::type& getArray() const {return std::get<N>(tupleOfArrays);}
const std::array<int, 3>& getTupleIndices() const {return tupleIndices;}
};
void B::accept (Visitor& visitor) {visitor.visit(this);}
void C::accept (Visitor& visitor) {visitor.visit(this);}
void D::accept (Visitor& visitor) {visitor.visit(this);}
class Object {
public:
virtual double foo (A*, A*) { std::cout << "Object::foo A,A\n"; return 3.14; }
virtual double foo (B*, B*) { std::cout << "Object::foo B,B\n"; return 3.14; }
virtual double foo (B*, C*) { std::cout << "Object::foo B,C\n"; return 3.14; }
virtual double foo (C*, B*) { std::cout << "Object::foo C,B\n"; return 3.14; }
virtual double foo (C*, C*) { std::cout << "Object::foo C,C\n"; return 3.14; }
virtual char foo (A*, A*, A*) const { std::cout << "Object::foo A,A,A\n"; return '&'; } // This is needed for the foo overload to be multiple dispatched, even if it is never used, otherwise the other possible foo overloads with three arguments will have no place to go to.
virtual char foo (C*, B*, D*) const { std::cout << "Object::foo C,B,D\n"; return '!'; } // Overload of foo with three arguments. Furthermore, the function itself is const and returns char instead of double. Simply define char fooMultipleDispatch (A*, A*, A*), ObjectFooVisitor<3> (the old ObjectFooVisitor now renamed to ObjectFooVisitor<2>) and overload multipleDispatch with char multipleDispatch (const ObjectFooVisitor<3>& visitor, const Z1<Is...>&, const Z2<Js...>&).
virtual void bar (A*, A*, A*) const { std::cout << "Object::bar A,A,A\n"; }
virtual void bar (B*, B*, B*) const { std::cout << "Object::bar B,B,B\n"; }
virtual void bar (B*, C*, B*) const { std::cout << "Object::bar B,C,B\n"; }
virtual void bar (B*, C*, C*) const { std::cout << "Object::bar B,C,C\n"; }
virtual void bar (B*, C*, D*) const { std::cout << "Object::bar B,C,D\n"; }
virtual void bar (C*, B*, D*) const { std::cout << "Object::bar C,B,D\n"; }
virtual void bar (C*, C*, C*) const { std::cout << "Object::bar C,C,C\n"; }
virtual void bar (D*, B*, C*) const { std::cout << "Object::bar D,B,C\n"; }
double fooMultipleDispatch (A*, A*);
char fooMultipleDispatch (A*, A*, A*);
void barMultipleDispatch (A*, A*, A*);
template <template <int...> class Z1, template <int...> class Z2, int... Is, int... Js>
double multipleDispatch (const ObjectFooVisitor<2>& visitor, const Z1<Is...>&, const Z2<Js...>&) {return foo (visitor.getArray<Is>()[Js]...);}
template <template <int...> class Z1, template <int...> class Z2, int... Is, int... Js>
char multipleDispatch (const ObjectFooVisitor<3>& visitor, const Z1<Is...>&, const Z2<Js...>&) const {return foo (visitor.getArray<Is>()[Js]...);}
template <template <int...> class Z1, template <int...> class Z2, int... Is, int... Js>
void multipleDispatch (const ObjectBarVisitor& visitor, const Z1<Is...>&, const Z2<Js...>&) {bar (visitor.getArray<Is>()[Js]...);}
};
class Thing {
public:
virtual int baz (A*, A*, A*) { std::cout << "Thing::baz A,A,A\n"; return 5; }
virtual int baz (B*, B*, B*) { std::cout << "Thing::baz B,B,B\n"; return 5; }
virtual int baz (B*, C*, B*) { std::cout << "Thing::baz B,C,B\n"; return 5; }
virtual int baz (B*, C*, C*) { std::cout << "Thing::baz B,C,C\n"; return 5; }
virtual int baz (B*, C*, D*) { std::cout << "Thing::baz B,C,D\n"; return 5; }
virtual int baz (C*, B*, D*) { std::cout << "Thing::baz C,B,D\n"; return 5; }
virtual int baz (C*, C*, C*) { std::cout << "Thing::baz C,C,C\n"; return 5; }
virtual int baz (D*, B*, C*) { std::cout << "Thing::baz D,B,C\n"; return 5; }
int bazMultipleDispatch (A*, A*, A*);
template <template <int...> class Z1, template <int...> class Z2, int... Is, int... Js>
int multipleDispatch (const ThingBazVisitor& visitor, const Z1<Is...>&, const Z2<Js...>&) {return baz (visitor.getArray<Is>()[Js]...);} // Since Thing only has baz interested in multiple dispatching, it does not need its own MultipleDispatch inner class like Object does (but if other Thing methods want multiple dispatching, then as in the Object::multipleDispatch overloads).
};
template <typename, typename, typename, int, int, typename, typename = void, int = 0> struct MultipleDispatcher;
template <typename T, typename V, typename R, int Num, int N, template <int...> class Z, int... Is, int I>
struct MultipleDispatcher<T, V, R, Num, N, Z<I, Is...>, typename std::enable_if<N != Num-1>::type> : MultipleDispatcher<T, V, R, Num, N, Z<I+1, Is...>, typename std::enable_if<N != Num-1>::type> {
T* t;
const V& visitor;
MultipleDispatcher (T* o, const V& v) : MultipleDispatcher<T, V, R, Num, N, Z<I+1, Is...>, typename std::enable_if<N != Num-1>::type>(o,v), t(o), visitor(v) {}
R execute();
};
template <typename T, typename V, typename R, int Num, int Last, template <int...> class Z, int... Is, int I>
struct MultipleDispatcher<T, V, R, Num, Last, Z<I, Is...>, typename std::enable_if<Last == Num-1>::type> : MultipleDispatcher<T, V, R, Num, Last, Z<I+1, Is...>, typename std::enable_if<Last == Num-1>::type> {
T* t;
const V& visitor;
MultipleDispatcher (T* o, const V& v) : MultipleDispatcher<T, V, R, Num, Last, Z<I+1, Is...>, typename std::enable_if<Last == Num-1>::type>(o,v), t(o), visitor(v) {}
R execute();
};
template <typename T, typename V, typename R, int Num, int N, template <int...> class Z, int... Is>
struct MultipleDispatcher<T, V, R, Num, N, Z<Num, Is...>, typename std::enable_if<N != Num-1>::type> {
T* t;
const V& visitor;
MultipleDispatcher (T* o, const V& v) : t(o), visitor(v) {}
R execute() {return R();} // End of recursion
};
template <typename T, typename V, typename R, int Num, int Last, template <int...> class Z, int... Is>
struct MultipleDispatcher<T, V, R, Num, Last, Z<Num, Is...>, typename std::enable_if<Last == Num-1>::type> { // This unique specialization is needed to avoid compiling ambiguity.
T* t;
const V& visitor;
MultipleDispatcher (T* o, const V& v) : t(o), visitor(v) {}
R execute() {return R();} // End of recursion
};
template <typename T, typename V, typename R, int Num, int N, template <int...> class Z, int... Is, int I>
R MultipleDispatcher<T, V, R, Num, N, Z<I, Is...>, typename std::enable_if<N != Num-1>::type>::execute() {
if (I == visitor.getTupleIndices()[N])
return MultipleDispatcher<T, V, R, Num, N+1, Z<0, I, Is...>, void>(t, visitor).execute(); // Do we need to specify the std::enable_if part here? Apparently not. We will allow N+1 to be anything, and there is apparently no ambiguity.
else
return MultipleDispatcher<T, V, R, Num, N, Z<I+1, Is...>, typename std::enable_if<N != Num-1>::type>::execute();
}
template <int...> struct index_sequence {};
template <int N, int... Is>
struct make_index_sequence_helper : make_index_sequence_helper<N-1, N-1, Is...> {};
template <int... Is>
struct make_index_sequence_helper<0, Is...> {
using type = index_sequence<Is...>;
};
template <int N>
using make_index_sequence = typename make_index_sequence_helper<N>::type;
template <typename, typename> struct ReverseHelper;
template <template <int...> class Z, typename Pack>
struct ReverseHelper<Z<>, Pack> {
using type = Pack;
};
template <template <int...> class Z, int First, int... Rest, int... Is>
struct ReverseHelper<Z<First, Rest...>, Z<Is...>> : ReverseHelper<Z<Rest...>, Z<First, Is...>> {};
template <typename> struct Reverse;
template <template <int...> class Z, int... Is>
struct Reverse<Z<Is...>> : ReverseHelper<Z<Is...>, Z<>> {};
template <typename T, typename V, typename R, int Num, int Last, template <int...> class Z, int... Is, int I>
R MultipleDispatcher<T, V, R, Num, Last, Z<I, Is...>, typename std::enable_if<Last == Num-1>::type>::execute() {
if (I == visitor.getTupleIndices()[Last])
return t->template multipleDispatch (visitor, typename Reverse<Z<I, Is...>>::type{}, make_index_sequence<Num>{}); // This compiles on GCC 4.9.2 but not on GCC 4.8.1. Template disambiguator needed.
else
return MultipleDispatcher<T, V, R, Num, Last, Z<I+1, Is...>, typename std::enable_if<Last == Num-1>::type>::execute();
}
double Object::fooMultipleDispatch (A* a1, A* a2) {
ObjectFooVisitor<2> visitor;
a1->accept(visitor); // Stores the dynamic type of a1
a2->accept(visitor); // and a2 into ObjectFooVisitor<2>'s array data members.
return MultipleDispatcher<Object, ObjectFooVisitor<2>, double, 2, 0, index_sequence<0>>(this, visitor).execute(); // 2 because there are two arguments in the Object::foo overloads.
}
char Object::fooMultipleDispatch (A* a1, A* a2, A* a3) {
ObjectFooVisitor<3> visitor;
a1->accept(visitor);
a2->accept(visitor);
a3->accept(visitor);
return MultipleDispatcher<Object, ObjectFooVisitor<3>, char, 3, 0, index_sequence<0>>(this, visitor).execute(); // 3 because there are three arguments in this particular Object::foo overload.
}
void Object::barMultipleDispatch (A* a1, A* a2, A* a3) {
ObjectBarVisitor visitor;
a1->accept(visitor);
a2->accept(visitor);
a3->accept(visitor);
MultipleDispatcher<Object, ObjectBarVisitor, void, 3, 0, index_sequence<0>>(this, visitor).execute(); // 3 because there are two arguments in the Object::foo overloads.
}
int Thing::bazMultipleDispatch (A* a1, A* a2, A* a3) {
ThingBazVisitor visitor;
a1->accept(visitor);
a2->accept(visitor);
a3->accept(visitor);
return MultipleDispatcher<Thing, ThingBazVisitor, int, 3, 0, index_sequence<0>>(this, visitor).execute(); // 3 because there are three arguments in the Thing::baz overloads.
}
// Test
int main() {
A* a[] = {new B, new C, new D};
Object* object = new Object;
double d = object->foo (a[0], a[1]); // Object::foo A,A (no multiple dispatch)
d = object->fooMultipleDispatch (a[0], a[1]); // Object::foo B,C
std::cout << "d = " << d << std::endl; // 3.12
const char k = object->fooMultipleDispatch (a[1], a[0], a[2]); // Object::foo C,B,D
std::cout << "k = " << k << std::endl; // !
object->bar (a[1], a[0], a[2]); // Object::bar A,A,A (no multiple dispatch)
object->barMultipleDispatch (a[1], a[0], a[2]); // Object::bar C,B,D
Thing* thing = new Thing;
int num = thing->baz (a[1], a[0], a[2]); // Thing::baz A,A,A (no multiple dispatch)
num = thing->bazMultipleDispatch (a[1], a[0], a[2]); // Thing::baz C,B,D
std::cout << "num = " << num << std::endl; // 5
}
最佳答案
经过一些复习之后,我会使用这样的东西:
必要的标题
#include <iostream>
#include <typeinfo>
#include <map>
#include <array>
#include <functional>
#include <stdexcept>
#include <algorithm>
dynamic_call:调用任何带有向下转换参数的函数,由调度程序使用
// base case: no arguments
template<typename Result>
Result dynamic_call (std::function<Result()> fun)
{
return fun();
}
template<typename Result>
Result dynamic_call (Result(*fun)())
{
return fun();
}
// one or more argument: dynamic_cast the first argument,
// recursively pass down the rest of them
template<typename Result, typename Arg0, typename FunArg0, typename ... Args, typename ... FunArgs>
Result dynamic_call (std::function<Result(FunArg0*, FunArgs*...)> fun, Arg0* arg0, Args*... args)
{
FunArg0* converted_arg0 = dynamic_cast<FunArg0*>(arg0);
if (converted_arg0 == nullptr)
throw std::runtime_error("Argument type error!");
std::function<Result(FunArgs*...)> helper = [converted_arg0, fun](FunArgs*... fun_args) -> Result
{
return fun(converted_arg0, fun_args...);
};
return dynamic_call(helper, args...);
}
template<typename Result, typename Arg0, typename FunArg0, typename ... Args, typename ... FunArgs>
Result dynamic_call (Result (*fun)(FunArg0*, FunArgs*...), Arg0* arg0, Args*... args)
{
std::function<Result(FunArg0*, FunArgs*...)> sfn(fun);
return dynamic_call(sfn, arg0, args...);
}
dispatcher:将一堆函数存储在一个map中,通过传递参数的实际动态类型找到它们
template <typename Result, typename ... Args>
class Dispatcher
{
public:
Result operator() (Args*... args)
{
key k{tiholder(typeid(*args))...};
typename map::iterator it = functions.find(k);
if (it == functions.end())
throw std::runtime_error("Function not found!");
return it->second(args...);
}
template <typename ... FunArgs>
void register_fn(std::function<Result(FunArgs*...)> fun)
{
auto lam = [fun](Args*... args) -> Result
{
return dynamic_call(fun, args...);
};
key k{tiholder(typeid(FunArgs))...};
functions[k] = lam;
}
template <typename ... FunArgs>
void register_fn(Result(*fun)(FunArgs*...))
{
return register_fn(std::function<Result(FunArgs*...)>(fun));
}
private:
struct tiholder
{
const std::type_info* ti;
tiholder(const std::type_info& ti) : ti(&ti) {}
bool operator< (const tiholder& other) const { return ti->before(*other.ti); }
};
static constexpr int PackSize = sizeof ... (Args);
using key = std::array<tiholder, PackSize>;
using value = std::function<Result(Args*...)>;
using map = std::map<key, value>;
map functions;
};
测试用例
struct Base { virtual ~Base() {} } ;
struct A : Base {};
struct B : Base {};
void foo1(A*,A*) { std::cout << "foo(A*,A*)\n"; }
void foo2(A*,B*) { std::cout << "foo(A*,B*)\n"; }
void foo3(B*,A*) { std::cout << "foo(B*,A*)\n"; }
void foo4(B*,B*) { std::cout << "foo(B*,B*)\n"; }
测试驱动程序和用户指南
int main ()
{
Base* x = new A;
Base* y = new B;
Dispatcher<void,Base,Base> foo;
foo.register_fn(foo1);
foo.register_fn(foo2);
foo.register_fn(foo3);
foo.register_fn(foo4);
foo(x,x);
foo(x,y);
foo(y,x);
foo(y,y);
}
关于c++ - 具有完全可维护性的多调度解决方案,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29286381/