使用宏迭代生成函数声明 [英] Generating function declaration using a macro iteration
问题描述
我试图使用宏生成函数声明
/ *目标:generate int f 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 :: type N(PARAM_ITER P(,e))
PROTO((int),f,(int)(a)(float)(b)
它将迭代处理下一个(name)
(type)分别由 NAME
或其中
...
有一个空宏参数。但是GCC抱怨
prototype.hpp:20:35:warning:ISO C99要求使用rest参数
ang子抱怨
ptype< void(int)> :: type f(int aprototype.hpp:20:1:warning:varargs参数缺少,但允许作为扩展名[-pedantic]
我认为这是因为下列原因:
#define FOO(X,...)
FOO(A);
我不传递参数
...
或每个(name)
或<$ c $
我可以申请吗? '现在使用类似于@James使用的技术来找到参数列表的长度。如果作为第二个参数,而不是
O
,ONT
传递,我将打印逗号和NAME
。以下是最终解决方案:/ *目标:生成void f(int a,float b)* /
/ pre>
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
$ b #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
#define STR(X)STR1(X)
int main(){
//正确打印
std :: cout< STR(PROTO((int),f,(int)(a)(float)(b)));
}
解决方案P99 有一个宏,它完全按照你想要的,我想,
P99_PROTOTYPE
。它有一个签名P99_PROTOTYPE(RT,NAME [,AT] *)
其中
RT
是返回类型(可能void
)和AT
是参数类型。参数类型列表可以为空,在这种情况下,它将替换为void
。
为C99而不是C ++。如果你的参数包含逗号,你会遇到特殊的困难。 C ++的令牌的语法滥用
<
和>
作为模板的括号表达式对预处理器特别糟糕。 C-preprocessor和C ++在语法层面上基本上是不兼容的语言。
P99通过检测宏接收到的参数数量,远离你所面临的困难一个电话和对边界案件的反应不同。
I'm trying to generate a function declaration using a macro
/* 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));
It will iteratively process the next
(name)
or(type)
byNAME
orPARAMS
respectively, with the...
having an empty macro argument. But GCC complains withprototype.hpp:20:35: warning: ISO C99 requires rest arguments to be used
And clang complains with
ptype<void (int)>::type f (int aprototype.hpp:20:1: warning: varargs argument missing, but tolerated as an extension [-pedantic]
I think this happens because of the following
#define FOO(X, ...) FOO(A);
Because I'm not passing an argument for the
...
or each of those(name)
or(type)
. Is there any simple work around I can apply?
I've now used a technique similar to the technique used by @James to find the length of a parameter list. If as second argument, instead of
O
,ONT
is passed, I will print the comma andNAME
. The following is the final solution:/* 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))
Test:
#define STR1(X) #X #define STR(X) STR1(X) int main() { // prints correctly std::cout << STR(PROTO((int), f, (int)(a)(float)(b))); }
解决方案P99 has a macro that does exactly what you want, I think, namely
P99_PROTOTYPE
. It has a "signature" ofP99_PROTOTYPE(RT, NAME [, AT]*)
where
RT
is the return type (may bevoid
) andAT
are the argument types. The list of argument types may be empty, in which case it is substituted byvoid
.Beware that P99 is made for C99 and not for C++. You'll encounter particular difficulties if your arguments contain commas. C++'s syntax abuse of tokens
<
and>
as bracketing expressions for templates is particularly bad for the preprocessor. C-preprocessor and C++ are basically incompatible languages on the syntax level.P99 gets away from the difficulties that you are facing by detecting the number of arguments that the macro receives on a call and reacts differently on the border cases.
这篇关于使用宏迭代生成函数声明的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!