2015-03-29 17 views
7

Come faccio a creare una macro che ha richiesto una quantità variabile di argomenti e la stampa con std :: cout? Scusa se questa è una domanda noob, non è stato possibile trovare nulla che chiarisca le macro variadiche dopo aver cercato la risposta.Come creare una macro variadic per std :: cout?

concettuale Esempio:

#include <iostream> 
#define LOG(...) std::cout << ... << ... << std::endl 
int main() { 
    LOG("example","output","filler","text"); 
    return 0; 
} 

visualizzerà:

exampleoutputfillertext 
+1

Perché? Perché? Perché? basta scrivere il codice –

risposta

6

Quando si utilizza le macro variadic è necessario __VA_ARGS__ per espandere tutti gli argomenti. Il problema tuttavia è che quegli argomenti sono separati da virgola. Presumibilmente separa semplicemente gli argomenti da una chiamata di funzione, ma poiché le macro funzionano con solo testo puoi effettivamente usare __VA_ARGS__ anche in altri contesti, dove un elenco separato da virgola ha senso.

Il trucco è possibile utilizzare è quello di definire il proprio operatore di virgola per std::ostream (il tipo di std::cout). Per esempio:

#include<iostream> 
#define LOG(...) std::cout , __VA_ARGS__ , std::endl 

template <typename T> 
std::ostream& operator,(std::ostream& out, const T& t) { 
    out << t; 
    return out; 
} 

//overloaded version to handle all those special std::endl and others... 
std::ostream& operator,(std::ostream& out, std::ostream&(*f)(std::ostream&)) { 
    out << f; 
    return out; 
} 

int main() { 
    LOG("example","output","filler","text"); 
    return 0; 
} 

Ora, l'invocazione LOG si espanderà a:

std::cout , "example" , "output" , "filler" , "text" , std::endl; 

e le virgole invocherà le virgola operatori di overload.

Se non ti piace il sovraccarico di operator, che inquina tutti i std::ostream -s, puoi incapsulare std::cout con la tua classe di logger speciale.

+0

non è '__VA_ARGS__' specifico per gcc? – vsoftco

+3

Per quanto ne so, __VA_ARGS__' è supportato in ogni compilatore C/C++ che supporta macro variadic in primo luogo. Le macro Variadic sono standard in C e C++ 11 ma non in C++. – CygnusX1

+0

grazie, non sapevo che lo facessero in C++ 11. risposta al punto, in aumento – vsoftco

1

Non è sicuro che esista un modo per definire una macro variadica in C++ (almeno, non un modo portabile). Perché non usi un approccio al modello variadico? Qualcosa come

#include <iostream> 

void LOG() {} 

template<typename Head, typename... Args> 
void LOG(const Head& head, const Args&... args) 
{ 
    std::cout << head << " "; 
    LOG(args...); 
} 

int main() 
{ 
    LOG("This", "is" , "the", 3, "rd test"); 
} 
+0

Hai bisogno di una condizione di terminazione per impedire che il modello sia ricorsivo all'infinito. – Peter

+0

@Peter è ciò che il 'void LOG()' fa – vsoftco

13

Non hai bisogno di macro di preprocessore per fare questo. Si può scrivere in ordinaria C++:

#include <iostream> 
#include <utility> 

void log(){} 

template<typename First, typename ...Rest> 
void log(First && first, Rest && ...rest) 
{ 
    std::cout << std::forward<First>(first); 
    log(std::forward<Rest>(rest)...); 
} 

int main() 
{ 
    log("Hello", "brave","new","world!\n"); 
    log("1", 2,std::string("3"),4.0,'\n'); 
} 

uscita:

Hellobravenewworld! 
1234 

si dovrebbe ricerca variadic templates e parameter packs piuttosto che macro variadic, che sono raramente utili nella moderna C++.

(gcc 4.9.2 -std = C++ 11)

+0

Ok! Grazie per il consiglio. Il codice è abbastanza brillante :-) – BlurryZombie

+0

@BlurryZombie Siete i benvenuti.Il codice è del tutto normale. Hai solo bisogno di conoscere le funzionalità che ho citato. –

Problemi correlati