Этот вопрос дает четкий пример того, как вы можете плохо использовать макросы. Чтобы увидеть другие примеры (и развлекаться), посмотрите этот вопрос .
Сказав это, я приведу примеры из реальной жизни того, что я считаю хорошим включением макросов.
Первый пример появляется в CppUnit , который является структурой модульного тестирования. Как и любая другая стандартная среда тестирования, вы создаете тестовый класс, а затем вам необходимо каким-то образом указать, какие методы следует запускать как часть теста.
#include <cppunit/extensions/HelperMacros.h>
class ComplexNumberTest : public CppUnit::TestFixture
{
CPPUNIT_TEST_SUITE( ComplexNumberTest );
CPPUNIT_TEST( testEquality );
CPPUNIT_TEST( testAddition );
CPPUNIT_TEST_SUITE_END();
private:
Complex *m_10_1, *m_1_1, *m_11_2;
public:
void setUp();
void tearDown();
void testEquality();
void testAddition();
}
Как видите, у класса есть блок макросов в качестве первого элемента. Если бы я добавил новый методtestSubtraction
, очевидно, что вам нужно сделать, чтобы включить его в тестовый прогон.
Эти макроблоки расширяются до чего-то вроде этого:
public:
static CppUnit::Test *suite()
{
CppUnit::TestSuite *suiteOfTests = new CppUnit::TestSuite( "ComplexNumberTest" );
suiteOfTests->addTest( new CppUnit::TestCaller<ComplexNumberTest>(
"testEquality",
&ComplexNumberTest::testEquality ) );
suiteOfTests->addTest( new CppUnit::TestCaller<ComplexNumberTest>(
"testAddition",
&ComplexNumberTest::testAddition ) );
return suiteOfTests;
}
Что бы вы предпочли читать и поддерживать?
Другой пример - инфраструктура Microsoft MFC, где вы отображаете функции на сообщения:
BEGIN_MESSAGE_MAP( CMyWnd, CMyParentWndClass )
ON_MESSAGE( WM_MYMESSAGE, OnMyMessage )
ON_COMMAND_RANGE(ID_FILE_MENUITEM1, ID_FILE_MENUITEM3, OnFileMenuItems)
// ... Possibly more entries to handle additional messages
END_MESSAGE_MAP( )
Итак, что же отличает «Хорошие Макросы» от ужасного злого?
Они выполняют задачу, которую нельзя упростить другим способом. Написание макроса для определения максимума между двумя элементами является неправильным, потому что вы можете добиться того же, используя метод шаблона. Но есть некоторые сложные задачи (например, отображение кодов сообщений на функции-члены), которые язык C ++ просто не выполняет элегантно.
Они имеют чрезвычайно строгое формальное использование. В обоих этих примерах макроблоки объявляются с помощью начального и конечного макросов, а промежуточные макросы будут появляться только внутри этих блоков. У вас нормальный C ++, вы на короткое время извиняете себя блоком макросов, а затем снова возвращаетесь в нормальное состояние. В примерах «злых макросов» макросы разбросаны по всему коду, и незадачливый читатель не может узнать, когда применяются правила C ++, а когда - нет.