我希望制作一个可变宏,只需为每个参数调用一个特定的函数(例如,最多6个)。到目前为止,我一直在MSVC中使用以下代码:
#define do_write2(x,y) do{do_write(x);do_write(y);}while(0)
#define do_write3(x,y,z) do{do_write(x);do_write(y);do_write(z);}while(0)
#define do_write4(x,y,z,w) do{do_write(x);do_write(y);do_write(z);do_write(w);}while(0)
#define do_write5(x,y,z,w,t) do{do_write(x);do_write(y);do_write(z);do_write(w);do_write(t);}while(0)
#define do_write6(x,y,z,w,t,u) do{do_write(x);do_write(y);do_write(z);do_write(w);do_write(t);do_write(u);}while(0)
#define expand(x) x
#define _get_write(_1,_2,_3,_4,_5,_6,name,...) name
#define dumpval(...) expand(_get_write(__VA_ARGS__,do_write6,do_write5,do_write4,do_write3,do_write2,do_write))expand((__VA_ARGS__))
由于MSVC中expand
的特殊处理需要__VA_ARGS__
,否则我
error C2660: 'do_write' : function does not take 6 arguments
但是,现在我需要在GCC中构建相同的代码,并且它有问题:
error: ‘do_write3’ was not declared in this scope
只需删除expand
包装就行了。但是,有没有"正确"如何在不使用#ifdef
的情况下编译代码?
答案 0 :(得分:1)
这里讨论了变量参数宏的各种技术:Variadic recursive preprocessor macros - is it possible?
以下是您可能感兴趣的一些实现。就个人而言,我认为假设您拥有C ++ 11支持,call_vla2
是最好的。如果无法做到这一点,请告诉我们您的问题。
#include <iostream>
// target function
void z(int i) {
std::cout << "[" << i << "]\n";
}
// 1. manually specifying the argument count
#define call1(a) do{z(a);}while(0)
#define call2(a,b) do{z(a);z(b);}while(0)
#define call3(a,b,c) do{z(a);z(b);z(c);}while(0)
#define call_n(n, ...) call ## n (__VA_ARGS__)
// 2. using a variable-length array (GCC compatible)
// thanks to https://stackoverflow.com/a/824769/6096046
#define call_vla(...) do { \
int args[] = { __VA_ARGS__ }; \
for(size_t i = 0; i < sizeof(args)/sizeof(*args); i ++) \
z(args[i]); \
} while(0)
// 3. using a variable-length array and C++11
#define call_vla2(...) for(auto x : { __VA_ARGS__ }) z(x);
// 4. using C++11 variadic templates
template <typename... T>
void call_n_times() {}
template <typename... T>
void call_n_times(int a, T... other) {
z(a), call_n_times(other...);
}
#define call_template(...) call_n_times(__VA_ARGS__)
// tests
int main() {
call_n(1, 88); call_n(3, 1,2,3);
call_vla(88); call_vla(1,2,3);
call_vla2(88); call_vla2(1,2,3);
call_template(88); call_template(1,2,3);
return 0;
}