Предположим, что мы будем игнорировать очевидные вещи, такие как защитники заголовков.
Иногда вы хотите сгенерировать код, который должен копировать/вставить прекомпилятором:
#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)
который позволяет закодировать следующим образом:
RAISE_ERROR_STL("Hello... The following values " << i << " and " << j << " are wrong") ;
А может генерировать сообщения типа:
Error Raised:
====================================
File : MyFile.cpp, line 225
Function : MyFunction(int, double)
Message : "Hello... The following values 23 and 12 are wrong"
Обратите внимание, что смешивание шаблонов с помощью макросов может привести к еще лучшим результатам (Т.е. автоматически генерируя значения бок о бок с их именами переменных)
В то же время, например, для генерации информации об отладке вам потребуется __FILE__ и/или __LINE__ некоторого кода. Ниже приведен классический для Visual C++:
#define WRNG_PRIVATE_STR2(z) #z
#define WRNG_PRIVATE_STR1(x) WRNG_PRIVATE_STR2(x)
#define WRNG __FILE__ "("WRNG_PRIVATE_STR1(__LINE__)") : ------------ : "
Как с помощью следующего кода:
#pragma message(WRNG "Hello World")
он генерирует сообщения типа:
C:\my_project\my_cpp_file.cpp (225) : ------------ Hello World
Другие времена, вам необходимо сгенерировать код, используя операторы конкатенации # и ##, такие как генерация геттеров и сеттеров для свойства (это для довольно ограниченных случаев).
Другие времена, вы будете генерировать код, чем не будет компилироваться, если используется с помощью функции, как:
#define MY_TRY try{
#define MY_CATCH } catch(...) {
#define MY_END_TRY }
который может быть использован в качестве
MY_TRY
doSomethingDangerous() ;
MY_CATCH
tryToRecoverEvenWithoutMeaningfullInfo() ;
damnThoseMacros() ;
MY_END_TRY
(до сих пор я видел только это тип кода, который правильно используется один раз)
Последнее, но не менее важное: знаменитый 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;
}
(Примечание: код копировать/вставить из повышающего страницы)
Который (имхо) лучше, чем std::for_each
.
Итак, макросы всегда полезны, потому что они находятся вне нормальных правил компилятора. Но я нахожу, что в большинстве случаев, когда я вижу один, они фактически остаются кодом C, никогда не переведенным на правильный C++.
В этой ситуации вам может быть лучше создать структуру CallbackArg. – 2008-09-19 04:24:24