我想定义很多函数调度程序。根据旗帜,我会打电话给其中一个。标志检查总是一样的,也是namings。
这是一个示例代码:
int myfunction(int a,int b)
{
if (flag)
return myfunction_flag1(a, b);
else
return myfunction_flag0(a, b);
}
因为这个代码会为我的每个函数重复一次(实际的usecase使用的行数多于其他行,如果没有,但是为了问题目的而简化了),我想把它写成一个MACRO。
#define DISPATCHER(function_type, function_name, ...) \
function_type function_name(__VA_ARGS__) \
{ \
if (flag) \
return function_name ## flag1(__VA_ARGS__); \
else \
return function_name ## flag0(__VA_ARGS__); \
} \
然后有很多:
DISPATCHER(int, myfunction, int a, int b)
DISPATCHER(int, myfunction2, int a, int b, int c)
DISPATCHER(int, myfunction3, int a)
...
但是,我无法调用function_name ## flag1(\__VA_ARGS__)
,因为\__VA_ARGS__
包含参数类型。
有没有办法以另一种方式做到这一点?
答案 0 :(得分:0)
一种可能性是将宏调用语法更改为更像DISPATCHER(int, myfunction2, int, a, int, b, int, c)
的内容,其中变量名称和类型作为单独的宏参数传递。然后,宏扩展可以在构建原型时使用类型信息,并在调用子函数时使用参数名称。这要求您按名称访问所有单个参数,因此您必须事先知道参数的数量。许多具有不同参数计数的函数会使这种方法变得相当尴尬。
另一种选择是重构函数以使用varargs
而不是单个参数。然后,宏扩展不需要处理参数列表,只需将其自己的va_list
传递给每个子函数(现在可以进行硬编码)。这样可以避免出现宏观问题,但您只是针对与varargs
相关的问题进行交易。
最近几次我需要做这样的事情,我刚刚编写了一个可以预处理源文件并生成所需代码的简短脚本。具有更好文本处理功能的语言(如Python或Ruby)使这个很多更容易。预处理器并不是专门为元编程设计的,所以虽然有可能让它适用于这样的事情,但它通常更快,更容易,并且更容易使用不同的工具。
答案 1 :(得分:0)
您不需要在此处指定参数名称;只要将参数名称与相应的参数名称匹配,宏中任何合理唯一的名称都可以解决问题。生成这些名称可能比传递它的工作更容易。
这让我们有了扩展这样的事情的任务:
DISPATCHER(int, myfunction, int, int)
DISPATCHER(int, myfunction2, int, int, int)
DISPATCHER(int, myfunction3, int)
我更喜欢跳转到...
语义相关的东西,所以我建议使用三参数宏,其中第三个参数本身是一个类型列表:
DISPATCHER(int, myfunction, (int, int))
DISPATCHER(int, myfunction2, (int, int, int))
DISPATCHER(int, myfunction3, (int))
使用boost预处理器,您可以执行以下操作:
#include <boost/preprocessor/repetition/enum.hpp>
#include <boost/preprocessor/tuple/size.hpp>
#include <boost/preprocessor/tuple/elem.hpp>
#include <boost/preprocessor/cat.hpp>
#define PARAMETER_M(z,OFFSET_,DATA_) \
BOOST_PP_TUPLE_ELEM(OFFSET_,DATA_) BOOST_PP_CAT(arg_,OFFSET_)
#define ARGUMENT_M(z,OFFSET_,DATA_) \
BOOST_PP_CAT(arg_,OFFSET_)
#define DISPATCH(RETVAL_,NAME_,ARGLIST_) \
RETVAL_ NAME_ ( BOOST_PP_ENUM(BOOST_PP_TUPLE_SIZE(ARGLIST_), PARAMETER_M,ARGLIST_) ) \
{ \
if (flag) return NAME_ ## flag1 \
( BOOST_PP_ENUM(BOOST_PP_TUPLE_SIZE(ARGLIST_), ARGUMENT_M, ARGLIST_) ); \
else return NAME_ ## flag0 \
( BOOST_PP_ENUM(BOOST_PP_TUPLE_SIZE(ARGLIST_), ARGUMENT_M, ARGLIST_) ); \
}
此实现使用BOOST_PP_ENUM
生成参数和参数列表。在这两种情况下,ARG
都是我们的类型元组(例如,(int,int,short,char*)
)。
PARAMETER_M
是MACRO
,它通过从类型列表中选择OFFSET_
个参数来生成参数列表,然后arg_
粘贴到OFFSET_
ARGUMENT_M
是MACRO
,只需将arg_
粘贴到OFFSET_
即可生成参数列表。