使用宏迭代生成函数声明 [英] Generating function declaration using a macro iteration

查看:203
本文介绍了使用宏迭代生成函数声明的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图使用宏生成函数声明

  / *目标: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)* / 
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))
/ pre>

测试:

  #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) by NAME or PARAMS respectively, with the ... having an empty macro argument. But GCC complains with

prototype.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 and NAME. 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" of

P99_PROTOTYPE(RT, NAME [, AT]*)

where RT is the return type (may be void) and AT are the argument types. The list of argument types may be empty, in which case it is substituted by void.

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆