4

我正在尝试使用宏生成函数声明

/* goal: generate int f(int a, float b) */
template<typename P>
struct ptype;

template<typename P>
struct ptype<void(P)> { typedef P type; };

#define NAMEe
#define COMMAe
#define COMMA ,

#define NAME(N) N PARAMS
#define PARAMS(P, ...) COMMA ## __VA_ARGS__ P NAME ## __VA_ARGS__
#define PARAM_ITER(P) P NAME

#define PROTO(R, N, P)  \
  ptype<void R>::type N (PARAM_ITER P (,e))

PROTO((int), f, (int)(a)(float)(b));

它将迭代地处理下一个(name)(type)通过NAMEPARAMS分别,...具有一个空的宏参数。但海湾合作委员会抱怨

prototype.hpp:20:35: warning: ISO C99 requires rest arguments to be used

铿锵的抱怨

ptype<void (int)>::type f (int aprototype.hpp:20:1: warning: varargs argument missing, but tolerated as an extension [-pedantic]

我认为这是因为以下原因

#define FOO(X, ...)
FOO(A);

因为我没有为这些...or 中的每一个(name)(type). 我可以申请任何简单的工作吗?


我现在使用了一种类似于@James 使用的技术来查找参数列表的长度。如果作为第二个参数,而不是O传递ONT,我将打印逗号和NAME。以下是最终解决方案:

/* goal: generate void f(int a, float b) */
template<typename P>
struct ptype;

template<typename P>
struct ptype<void(P)> { typedef P type; };

#define TYPE_DO(X) X
#define TYPE_DONT(X)
#define TYPE_MAYBE(X, A, ...) TYPE_D ## A (X)

#define COMMA_DO ,
#define COMMA_DONT
#define COMMA_MAYBE(A, B, ...) COMMA_D ## B

#define NAME_DO NAME
#define NAME_DONT
#define NAME_MAYBE(A, B, ...) NAME_D ## B

#define NAME(N) N PARAMS
#define PARAMS(...) COMMA_MAYBE(__VA_ARGS__,O,O) TYPE_MAYBE(__VA_ARGS__,O,O) \
                    NAME_MAYBE(__VA_ARGS__,O,O)
#define PARAM_ITER(P) P NAME

#define PROTO(R, N, P)  \
  ptype<void R>::type N (PARAM_ITER P (D,ONT))

测试:

#define STR1(X) #X
#define STR(X) STR1(X)

int main() {
  // prints correctly
  std::cout << STR(PROTO((int), f, (int)(a)(float)(b)));
}
4

2 回答 2

6

要解决“ FOO”问题,您可以根据变量参数包的数量选择不同的宏。这是第一个镜头:

// These need to be updated to handle more than three arguments:
#define PP_HAS_ARGS_IMPL2(_1, _2, _3, N, ...) N
#define PP_HAS_ARGS_SOURCE() MULTI, MULTI, ONE, ERROR

#define PP_HAS_ARGS_IMPL(...) PP_HAS_ARGS_IMPL2(__VA_ARGS__)
#define PP_HAS_ARGS(...)      PP_HAS_ARGS_IMPL(__VA_ARGS__, PP_HAS_ARGS_SOURCE())

#define FOO_ONE(x)     ONE_ARG:    x
#define FOO_MULTI(...) MULTI_ARG:  __VA_ARGS__

#define FOO_DISAMBIGUATE2(has_args, ...) FOO_ ## has_args (__VA_ARGS__)
#define FOO_DISAMBIGUATE(has_args, ...) FOO_DISAMBIGUATE2(has_args, __VA_ARGS__)
#define FOO(...) FOO_DISAMBIGUATE(PP_HAS_ARGS(__VA_ARGS__), __VA_ARGS__)

使用示例:

FOO(1)     // replaced by ONE_ARG:   1
FOO(1, 2)  // replaced by MULTI_ARG: 1, 2

(我会尝试重新审视它以清理它;我认为那里肯定有一些不必要的宏。我没有机会研究你描述的更广泛的问题,所以我不确定这是否能解决那也是。也可能有一种更简单的方法来解决这个问题......我对可变参数宏不是特别熟悉。这在 mcpp 上进行了干净的预处理。)

于 2011-03-18T17:53:01.337 回答
2

我认为P99有一个宏可以完全满足您的要求,即P99_PROTOTYPE. 它有一个“签名”

P99_PROTOTYPE(RT, NAME [, AT]*)

其中RT是返回类型(可能是void),AT是参数类型。参数类型列表可能为空,在这种情况下,它被替换为void.

请注意,P99 是为 C99 而不是为 C++ 制作的。如果你的论点包含逗号,你会遇到特别的困难。C++ 对标记的语法滥用<>作为模板的括号表达式对预处理器尤其不利。C 预处理器和 C++ 在语法级别上基本上是不兼容的语言。

P99 通过检测宏在调用中接收的参数数量以及对边界情况的不同反应来摆脱您所面临的困难。

于 2011-03-19T17:17:14.483 回答