Questa domanda fornisce un chiaro esempio di come è possibile utilizzare male le macro. Per vedere altri esempi (e divertirti) vedi questa domanda .
Detto questo, fornirò esempi reali di ciò che considero una buona incorporazione di macro.
Il primo esempio appare in CppUnit , che è un framework di unit test. Come qualsiasi altro framework di test standard, crei una classe di test e quindi devi in qualche modo specificare quali metodi dovrebbero essere eseguiti come parte del 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();
}
Come puoi vedere, la classe ha un blocco di macro come primo elemento. Se ho aggiunto un nuovo metodotestSubtraction
, è ovvio che cosa è necessario fare per includerlo nell'esecuzione del test.
Questi macro blocchi si espandono in qualcosa del genere:
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;
}
Quale preferiresti leggere e mantenere?
Un altro esempio è nel framework Microsoft MFC, in cui si mappano le funzioni ai messaggi:
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( )
Quindi, quali sono le cose che distinguono i "Macro buoni" dall'orribile genere malvagio?
Eseguono un compito che non può essere semplificato in nessun altro modo. Scrivere una macro per determinare un massimo tra due elementi è sbagliato, perché puoi ottenere lo stesso usando un metodo modello. Ma ci sono alcune attività complesse (ad esempio, la mappatura dei codici dei messaggi alle funzioni dei membri) che il linguaggio C ++ non gestisce in modo elegante.
Hanno un uso estremamente rigoroso e formale. In entrambi questi esempi i blocchi di macro vengono annunciati avviando e terminando le macro, e le macro tra di esse appariranno solo all'interno di questi blocchi. Hai C ++ normale, ti scusi brevemente con un blocco di macro e poi torni alla normalità. Negli esempi di "macro malvagie", le macro sono sparse in tutto il codice e il lettore sfortunato non ha modo di sapere quando si applicano le regole C ++ e quando non lo fanno.