Joh*_*itb 4 c++ c99 c-preprocessor variadic-macros c++11
我正在尝试使用宏生成函数声明
/* 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));
Run Code Online (Sandbox Code Playgroud)
它将使用具有空的宏参数来迭代地处理下一个(name)
或(type)
按NAME
或PARAMS
分别...
。但海湾合作委员会抱怨
prototype.hpp:20:35: warning: ISO C99 requires rest arguments to be used
Run Code Online (Sandbox Code Playgroud)
和c抱怨
ptype<void (int)>::type f (int aprototype.hpp:20:1: warning: varargs argument missing, but tolerated as an extension [-pedantic]
Run Code Online (Sandbox Code Playgroud)
我认为这是由于以下原因
#define FOO(X, ...)
FOO(A);
Run Code Online (Sandbox Code Playgroud)
因为我没有通过的一个参数...
或每一类又(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))
Run Code Online (Sandbox Code Playgroud)
测试:
#define STR1(X) #X
#define STR(X) STR1(X)
int main() {
// prints correctly
std::cout << STR(PROTO((int), f, (int)(a)(float)(b)));
}
Run Code Online (Sandbox Code Playgroud)
要解决“ 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__)
Run Code Online (Sandbox Code Playgroud)
用法示例:
FOO(1) // replaced by ONE_ARG: 1
FOO(1, 2) // replaced by MULTI_ARG: 1, 2
Run Code Online (Sandbox Code Playgroud)
(我将尝试重新检查它以进行清理;我认为那里肯定有一些不必要的宏。我没有机会研究您所描述的更广泛的问题,所以我不确定这是否可以解决也可能有一种更简单的方法来解决该问题……我对可变参宏不是特别熟悉。它在mcpp上进行了清晰的预处理。)