To pytanie daje jasny przykład tego, jak źle korzystać z makr. Aby zobaczyć inne przykłady (i się bawić), zobacz to pytanie .
Powiedziawszy to, podam przykłady z tego, co uważam za dobre włączenie makr.
Pierwszy przykład pojawia się w CppUnit , który jest strukturą testów jednostkowych. Jak każda inna standardowa platforma testowa, tworzysz klasę testową, a następnie musisz w jakiś sposób określić, które metody powinny być uruchamiane w ramach testu.
#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();
}
Jak widać, klasa ma blok makr jako pierwszy element. Jeśli dodam nową metodętestSubtraction
, oczywiste jest, co musisz zrobić, aby włączyć ją do uruchomienia testowego.
Te bloki makr rozwijają się do czegoś takiego:
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;
}
Które wolisz czytać i utrzymywać?
Innym przykładem jest platforma Microsoft MFC, w której mapujesz funkcje na wiadomości:
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( )
Jakie są zatem rzeczy, które odróżniają „Dobre makra” od okropnego zła?
Wykonują zadanie, którego nie można uprościć w żaden inny sposób. Pisanie makra w celu ustalenia maksimum między dwoma elementami jest niepoprawne, ponieważ można to zrobić przy użyciu metody szablonu. Ale są pewne złożone zadania (na przykład mapowanie kodów komunikatów na funkcje składowe), których język C ++ po prostu nie obsługuje elegancko.
Mają wyjątkowo surowe, formalne zastosowanie. W obu tych przykładach makra bloki są ogłaszane przez makra początkowe i końcowe, a makra między nimi będą pojawiać się tylko wewnątrz tych bloków. Masz normalny C ++, krótko usprawiedliwiasz się blokiem makr, a następnie wracasz do normy. W przykładach „złych makr” makra są rozproszone po całym kodzie, a nieszczęsny czytelnik nie ma możliwości dowiedzenia się, kiedy obowiązują reguły C ++, a kiedy nie.