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

/* 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

和c提示
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);

因为我没有传递...或每个(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)));
}

最佳答案

P99有一个宏,可以满足您的需求,即P99_PROTOTYPE。它具有以下特征:

P99_PROTOTYPE(RT, NAME [, AT]*)

其中RT是返回类型(可以是void),而AT是参数类型。参数类型列表可以为空,在这种情况下,它由void代替。

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

通过检测宏在调用中接收到的参数数量并对边界情况做出不同的 react ,P99摆脱了您面临的困难。

09-11 15:01