标语可能不是很具描述性,但我无法想出更好的标语。但是,我希望能够解释这个问题。
我有一个框架,可以松散地映射到以下演示代码:
struct OpaqueStruct {
// OpaqueStruct allows introspection of it's members
// using templatized inrospect()
class OpaqueStruct {
int i;
double d;
void* p;
public:
template <class T> void introspect(T visitor) {
visitor(i);
visitor(d);
visitor(p);
}
};
template <class T> struct FunkyCaller {
FunkyCaller(T* obj, int arg1, int arg2);
template <class A> void operator() (A a) {
obj->funky_impl(a, arg1, arg2);
}
private:
T* obj;
int arg1;
int arg2;
};
template <class T> struct FunkyCaller2 {
// similar to FunkyCaller, but calls
// this->funky2_impl(arg);
};
// Benemoth is full of logic, code, data and lines
class Benemoth {
OpaqueStruct opaque_data;
void funky(int arg1, double arg2) {
// Need to do something funky, taking args and opaque struct
// as input
opaque_data.introspect(FunkyCaller<Benemoth>(this, arg1, arg2));
}
void funky2(const char* arg) {
// Need to do something funky, taking args and opaque struct
// as input
// opaque_data.introspect(FunkyCaller2<Benemoth>(this, arg));
}
public:
template <class ARG>
void funky_impl(ARG a, int arg1, int arg2);
};
有很多代码,但我希望这个想法是可见的 - Benemoth中有不同的功能,需要以不同的方式处理opaque_data。我现在所拥有的设置,以及我在这里展示的设置,都有效。但是,我不喜欢它,因为每次我需要实现一个新函数来执行OpaqueData
的新功能时,我需要为它创建一个“调用者”类。这使代码维护变得困难,因为代码受到那些“呼叫者”的污染。任何人都需要进行逆向工程,必须从funky()
导航到FunkyCaller()
到funky_impl()
。不太好。
我已经考虑过了什么?
funky()
看起来像opaque_data.introspect([this, arg1, arg2](auto datum) { this->funky_impl(datum, arg1, arg2); });
。不幸的是,我们的项目尚未准备好使用C ++ 14 std::bind
s。无法使它工作,因为它们都需要指定参数类型 - lambdas要求你指定参数类型,通过想要指向成员的指针来绑定有没有人看到任何减少代码混乱的方法?我没有,但可能我错过了什么?