C++ 如何创建运行时子类化系统
我正在做一个可以在运行时定义的子类化系统。我有一个子类转发表的方法(C++ 如何创建运行时子类化系统,c++,metaprogramming,c-preprocessor,C++,Metaprogramming,C Preprocessor,我正在做一个可以在运行时定义的子类化系统。我有一个子类转发表的方法(std::map),如果表中没有方法,则使用超类方法 示例(函数参数和返回类型不是问题,我只是简化了它): 它对我来说工作得很好,只是我必须重复参数,一次是类型(inta,intb),一次是调用底层函数(a,b)。我想知道是否有更好的方法来做到这一点。如果您想消除声明中参数名的冗余(一次在声明列表中以其类型出现,一次在调用列表中以名称出现),您可以通过将名称和类型作为两个单独的列表提供来实现,然后用一个合适的双参数映射宏将它们压
std::map
),如果表中没有方法,则使用超类方法
示例(函数参数和返回类型不是问题,我只是简化了它):
它对我来说工作得很好,只是我必须重复参数,一次是类型(
inta,intb
),一次是调用底层函数(a,b
)。我想知道是否有更好的方法来做到这一点。如果您想消除声明中参数名的冗余(一次在声明列表中以其类型出现,一次在调用列表中以名称出现),您可以通过将名称和类型作为两个单独的列表提供来实现,然后用一个合适的双参数映射宏将它们压缩在一起
假设上述内容是准确的,那么实际的参数名称似乎也不太重要,因此您可以通过预定义一个伪名称列表,并将其排除在声明的可见部分之外,从而进一步简化声明:
#define NARGS(...) NARGS_(__VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
#define NARGS_(_10, _9, _8, _7, _6, _5, _4, _3, _2, _1, N, ...) N
#define CAT(A, B) CAT_(A, B)
#define CAT_(A, B) A##B
#define ID(...) __VA_ARGS__
#define APPEND(L, E) ID(L),E
#define FIRST(A, ...) A
#define REST(A, ...) __VA_ARGS__
#define ZIP(F, L1, L2) CAT(ZIP_, ID(NARGS L1))(F, L1, L2)
#define ZIP_4(F, L1, L2) F(ID(FIRST L1), ID(FIRST L2)), ZIP_3(F, (ID(REST L1)), (ID(REST L2)))
#define ZIP_3(F, L1, L2) F(ID(FIRST L1), ID(FIRST L2)), ZIP_2(F, (ID(REST L1)), (ID(REST L2)))
#define ZIP_2(F, L1, L2) F(ID(FIRST L1), ID(FIRST L2)), ZIP_1(F, (ID(REST L1)), (ID(REST L2)))
#define ZIP_1(F, L1, L2) F(ID(FIRST L1), ID(FIRST L2))
#define ZIP_0(F, L1, L2)
#define GENSYMS (_0, _1, _2, _3, _4, _5, _6, _7, _8, _9)
#define runtime_subclass_method(Superclass,rtype,method,args) \
rtype method(ZIP(EMIT_DECL, args, GENSYMS)) { \
if( table.count(#method) == 0 ) return Superclass::method(ZIP(EMIT_CALL, args, GENSYMS)); \
return table.at(#method)(this, ID(ZIP(EMIT_CALL, args, GENSYMS))); \
}
#define EMIT_DECL(T, N) T N
#define EMIT_CALL(T, N) N
runtime_subclass_method(Superclass,int,doSomething,(int,int))
这个例子中的大多数都是实用工具(比如CAT
)。扩展ZIP
、NARGS
和GENSYMS
以接受更多的参数(四个参数实际上有点小)应该是微不足道的
方法声明只接受一个参数类型列表,将它们与声明预定义列表中的名称组合在一起,并将长度与名称组合在一起以生成调用列表。我想知道怎么做,但您说您已经解决了映射中函数签名的问题。那么可变模板是否有效?像
template void doSomething(Args…Args){table.at(“doSomething”)(这个,Args…}
@leemes这样做是不可行的,因为我需要doSomething
覆盖超类::doSomething
,你知道我的意思吗?顺便说一下,我用void*
解决了参数传递问题,并将其转换为正确的std::function
变量。为什么?您仍然必须将其作为代码编写,因此对我来说,使用传统的虚拟函数似乎更明智。std::函数很可能是用解释语言定义的,比如Lua或Python。
#define runtime_subclass_begin(Superclass) //...
#define runtime_subclass_method(Superclass,rtype,method,args_def,args_call) //...
#define runtime_subclass_end
#define GROUP(...) __VA_ARGS__
runtime_subclass_begin(Superclass)
runtime_subclass_method(Superclass,int,doSomething,GROUP(int a,int b),GROUP(a,b))
runtime_subclass_end
#define NARGS(...) NARGS_(__VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
#define NARGS_(_10, _9, _8, _7, _6, _5, _4, _3, _2, _1, N, ...) N
#define CAT(A, B) CAT_(A, B)
#define CAT_(A, B) A##B
#define ID(...) __VA_ARGS__
#define APPEND(L, E) ID(L),E
#define FIRST(A, ...) A
#define REST(A, ...) __VA_ARGS__
#define ZIP(F, L1, L2) CAT(ZIP_, ID(NARGS L1))(F, L1, L2)
#define ZIP_4(F, L1, L2) F(ID(FIRST L1), ID(FIRST L2)), ZIP_3(F, (ID(REST L1)), (ID(REST L2)))
#define ZIP_3(F, L1, L2) F(ID(FIRST L1), ID(FIRST L2)), ZIP_2(F, (ID(REST L1)), (ID(REST L2)))
#define ZIP_2(F, L1, L2) F(ID(FIRST L1), ID(FIRST L2)), ZIP_1(F, (ID(REST L1)), (ID(REST L2)))
#define ZIP_1(F, L1, L2) F(ID(FIRST L1), ID(FIRST L2))
#define ZIP_0(F, L1, L2)
#define GENSYMS (_0, _1, _2, _3, _4, _5, _6, _7, _8, _9)
#define runtime_subclass_method(Superclass,rtype,method,args) \
rtype method(ZIP(EMIT_DECL, args, GENSYMS)) { \
if( table.count(#method) == 0 ) return Superclass::method(ZIP(EMIT_CALL, args, GENSYMS)); \
return table.at(#method)(this, ID(ZIP(EMIT_CALL, args, GENSYMS))); \
}
#define EMIT_DECL(T, N) T N
#define EMIT_CALL(T, N) N
runtime_subclass_method(Superclass,int,doSomething,(int,int))