Recentemente ho letto Effective C++ Second Edition di Scott Meyers per migliorare le best practice C++. Uno dei suoi elementi elencati incoraggia i programmatori C++ ad evitare le macro pre-processore e "preferisce il compilatore". È arrivato a dire che non ci sono quasi ragioni per le macro in C++ a parte #include e # ifdef/# ifndef.Le macro di pre-processore per le istruzioni di registro di debug hanno una posizione in C++?
sono d'accordo con il suo ragionamento, come si può realizzare la seguente macro
#define min(a,b) ((a) < (b) ? (a) : (b))
con il seguente linguaggio C++ dispone
template<class T>
inline const T & min(const T & a, const T & b) {
return a < b ? a : b;
}
dove in linea dà il compilatore la possibilità di rimuovere la chiamata di funzione e inserisci codice e modello inline in grado di gestire più tipi di dati con operatore sovraccarico o integrato>.
EDIT-- Questa dichiarazione modello non corrisponde completamente alla macro indicata se il tipo di dati di a e b differiscono. Vedi il commento di Pete per un esempio.
Tuttavia, sono curioso di sapere se l'utilizzo di macro per la registrazione di debug è un uso valido in C++. Se il metodo che presento di seguito non è una buona pratica, qualcuno sarebbe gentile a suggerire un modo alternativo?
Sono stato codificato in Objective-C per l'ultimo anno e uno dei miei motori 2D preferiti (cocos2d) ha utilizzato una macro per creare istruzioni di registrazione. La macro è la seguente:
/*
* if COCOS2D_DEBUG is not defined, or if it is 0 then
* all CCLOGXXX macros will be disabled
*
* if COCOS2D_DEBUG==1 then:
* CCLOG() will be enabled
* CCLOGERROR() will be enabled
* CCLOGINFO() will be disabled
*
* if COCOS2D_DEBUG==2 or higher then:
* CCLOG() will be enabled
* CCLOGERROR() will be enabled
* CCLOGINFO() will be enabled
*/
#define __CCLOGWITHFUNCTION(s, ...) \
NSLog(@"%s : %@",__FUNCTION__,[NSString stringWithFormat:(s), ##__VA_ARGS__])
#define __CCLOG(s, ...) \
NSLog(@"%@",[NSString stringWithFormat:(s), ##__VA_ARGS__])
#if !defined(COCOS2D_DEBUG) || COCOS2D_DEBUG == 0
#define CCLOG(...) do {} while (0)
#define CCLOGWARN(...) do {} while (0)
#define CCLOGINFO(...) do {} while (0)
#elif COCOS2D_DEBUG == 1
#define CCLOG(...) __CCLOG(__VA_ARGS__)
#define CCLOGWARN(...) __CCLOGWITHFUNCTION(__VA_ARGS__)
#define CCLOGINFO(...) do {} while (0)
#elif COCOS2D_DEBUG > 1
#define CCLOG(...) __CCLOG(__VA_ARGS__)
#define CCLOGWARN(...) __CCLOGWITHFUNCTION(__VA_ARGS__)
#define CCLOGINFO(...) __CCLOG(__VA_ARGS__)
#endif // COCOS2D_DEBUG
Questa macro fornisce un'incredibile utilità che desidero incorporare nei miei programmi C++. Scrivere una dichiarazione di registro utile è così semplice come
CCLOG(@"Error in x due to y");
Che cosa è ancora migliore, è che se il COCOS2D_DEBUG è impostato su 0, allora queste dichiarazioni non vedono mai la luce del giorno. Non esiste un sovraccarico per il controllo di un'istruzione condizionale per verificare se è necessario utilizzare le istruzioni di registrazione. Questo è conveniente quando si passa dalla fase di sviluppo alla produzione. Come si potrebbe ricreare lo stesso effetto in C++?
Quindi questo tipo di macro appartiene a un programma C++? C'è un modo migliore, più C++ per farlo?
Credo che il tuo "CCLOG()" sia un eccellente esempio di dove le macro sono utili e appropriate. IMHO ... – paulsm4
Um, quella funzione di template 'min' fa ** not ** fa la stessa cosa della macro. Provalo con 'min (1, 2L)'. –
@PeteBecker Non sono un guru con i modelli, ma potrebbe essere il caso perché 1 è un int e 2L è un lungo? La dichiarazione modello che ho fornito genererà solo funzioni per due oggetti dello stesso tipo. –