Digamos que ignoraremos coisas óbvias, como guardas de cabeçalho.
Às vezes, você deseja gerar código que precisa ser copiado / colado pelo pré-compilador:
#define RAISE_ERROR_STL(p_strMessage) \
do \
{ \
try \
{ \
std::tstringstream strBuffer ; \
strBuffer << p_strMessage ; \
strMessage = strBuffer.str() ; \
raiseSomeAlert(__FILE__, __FUNCSIG__, __LINE__, strBuffer.str().c_str()) \
} \
catch(...){} \
{ \
} \
} \
while(false)
que permite codificar isso:
RAISE_ERROR_STL("Hello... The following values " << i << " and " << j << " are wrong") ;
E pode gerar mensagens como:
Error Raised:
====================================
File : MyFile.cpp, line 225
Function : MyFunction(int, double)
Message : "Hello... The following values 23 and 12 are wrong"
Observe que a mistura de modelos com macros pode levar a resultados ainda melhores (ou seja, gerar automaticamente os valores lado a lado com seus nomes de variáveis)
Outras vezes, você precisa do __FILE__ e / ou __LINE__ de algum código, para gerar informações de depuração, por exemplo. A seguir, é um clássico do Visual C ++:
#define WRNG_PRIVATE_STR2(z) #z
#define WRNG_PRIVATE_STR1(x) WRNG_PRIVATE_STR2(x)
#define WRNG __FILE__ "("WRNG_PRIVATE_STR1(__LINE__)") : ------------ : "
Como no código a seguir:
#pragma message(WRNG "Hello World")
gera mensagens como:
C:\my_project\my_cpp_file.cpp (225) : ------------ Hello World
Outras vezes, você precisa gerar código usando os operadores de concatenação # e ##, como gerar getters e setters para uma propriedade (isso é para casos bastante limitados).
Outras vezes, você irá gerar código que não será compilado se usado por meio de uma função, como:
#define MY_TRY try{
#define MY_CATCH } catch(...) {
#define MY_END_TRY }
Qual pode ser usado como
MY_TRY
doSomethingDangerous() ;
MY_CATCH
tryToRecoverEvenWithoutMeaningfullInfo() ;
damnThoseMacros() ;
MY_END_TRY
(ainda assim, eu só vi esse tipo de código usado corretamente uma vez )
Por último, mas não menos importante, o famoso boost::foreach
!!!
#include <string>
#include <iostream>
#include <boost/foreach.hpp>
int main()
{
std::string hello( "Hello, world!" );
BOOST_FOREACH( char ch, hello )
{
std::cout << ch;
}
return 0;
}
(Nota: cópia de código / colada na página inicial do impulso)
Qual é (IMHO) muito melhor do que std::for_each
.
Portanto, as macros são sempre úteis porque estão fora das regras normais do compilador. Mas acho que na maioria das vezes vejo um, eles são efetivamente restos do código C nunca convertidos em C ++ apropriado.