Questa domanda fornisce un chiaro esempio di come è possibile utilizzare male le macro.
Per vedere altri esempi (ed essere intrattenuti) vedi questa domanda .
Detto questo, darò esempi reali di ciò che considero una buona integrazione di macro.
Il primo esempio appare in CppUnit , che è un framework di test unitario. Come qualsiasi altro framework di test standard, crei una classe di test e quindi devi in qualche modo specificare quali metodi devono 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 metodo testSubtraction
, è ovvio che cosa devi fare per averlo incluso nell'esecuzione del test.
Questi blocchi macro 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 preferisci leggere e mantenere?
Un altro esempio è nel framework Microsoft MFC, dove 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 "Good Macros" dal tipo orribile e malvagio?
-
Eseguono un'attività che non può essere semplificata in nessun altro modo. Scrivere una macro per determinare un massimo tra due elementi è sbagliato, perché puoi ottenere lo stesso usando un metodo di modello. Ma ci sono alcune attività complesse (ad esempio, mappare i codici dei messaggi alle funzioni dei membri) che il linguaggio C ++ non gestisce in modo elegante.
-
Hanno un uso formale estremamente rigoroso. In entrambi questi esempi i blocchi macro vengono annunciati con le macro iniziali e finali e le macro intermedie appariranno sempre all'interno di questi blocchi. Hai un normale C ++, 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.