C预处理器:调用与父相同参数的函数

时间:2017-10-27 15:29:49

标签: c preprocessor variadic-macros

我想定义很多函数调度程序。根据旗帜,我会打电话给其中一个。标志检查总是一样的,也是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__包含参数类型。 有没有办法以另一种方式做到这一点?

2 个答案:

答案 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_MMACRO,它通过从类型列表中选择OFFSET_个参数来生成参数列表,然后arg_粘贴到OFFSET_

ARGUMENT_MMACRO,只需将arg_粘贴到OFFSET_即可生成参数列表。