2016-07-04 3 views
1

Ich bin auf der Suche nach einem variadic Makro, das einfach eine bestimmte Funktion für jedes Argument (sagen wir bis zu 6) aufruft. Bisher habe ich den folgenden Code in MSVC wurde unter Verwendung von:Portable Variadic Makro

#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__)) 

Die expand aufgrund einer besonderen Umgang mit __VA_ARGS__ in MSVC benötigt wird, sonst bekomme ich

error C2660: 'do_write' : function does not take 6 arguments 

Aber jetzt muss ich bauen den gleichen Code in GCC, und seine Probleme mit ihm:

error: ‘do_write3’ was not declared in this scope 

einfaches Entfernen der expand Wrapper funktioniert der Trick. Gibt es jedoch eine "richtige" Möglichkeit, den Code in beiden Fällen kompilieren zu lassen, ohne #ifdef zu verwenden?

+3

Muß * dies * mit Makros geschehen? Kannst du 'C++ 11' verwenden? –

+0

Ich denke, ich könnte es umschreiben, um variadische Vorlagen zu verwenden, der Code ist ziemlich alt, also habe ich nie über diese Möglichkeit nachgedacht. – riv

Antwort

1

Es gibt verschiedene Techniken für variable Argument Makros, die hier beschrieben: Variadic recursive preprocessor macros - is it possible?

Hier einige Implementierungen sind, die Sie interessieren könnten Ich persönlich denke call_vla2 das Beste ist, vorausgesetzt, Sie haben C++ 11-Unterstützung. . Wenn dies nicht möglich ist, erzählen Sie uns mehr über Ihr Problem.

#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; 
}