This question gives a clear example of how you can use macros badly.
To see other examples (and be entertained) see this question.
Having said that, I'll give real world examples of what I consider to be good incorporation of macros.
The first example appears in CppUnit, which is a unit testing framework. Like any other standard testing framework, you create a test class and then you have to somehow specify which methods should be run as part of the test.
#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();
}
As you can see, the class has a block of macros as it's first element. If I added a new method testSubtraction
, it's obvious what you need to do to have it included in the test run.
These macro blocks expand out to something like this:
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;
}
Which would YOU prefer to read and maintain?
Another example is in the Microsoft MFC framework, where you map functions to messages:
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( )
So, what are the things which distinguish "Good Macros" from the horrible evil kind?
They perform a task which cannot be simplified any other way. Writing a macro to determine a maximum between two elements is wrong, because you can achieve the same using a template method. But there are some complex tasks (for example, mapping message codes to member functions) which the C++ language just doesn't handle elegantly.
They have an extremely strict, formal usage. In both of these examples the macro blocks are announced by starting and ending macros, and the inbetween macros will only ever appear inside these blocks. You have normal C++, you briefly excuse yourself with a block of macros, and then you go back to normal again. In the "evil macros" examples, the macros are scattered throughout the code and the hapless reader has no way of knowing when the C++ rules apply and when they do not.