Cette question donne un exemple clair de la façon dont vous pouvez mal utiliser les macros. Pour voir d'autres exemples (et se divertir) voir cette question .
Cela dit, je vais donner des exemples concrets de ce que je considère comme une bonne incorporation des macros.
Le premier exemple apparaît dans CppUnit , qui est un framework de tests unitaires. Comme tout autre framework de test standard, vous créez une classe de test, puis vous devez en quelque sorte spécifier les méthodes à exécuter dans le cadre du 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();
}
Comme vous pouvez le voir, la classe a un bloc de macros comme premier élément. Si j'ai ajouté une nouvelle méthode testSubtraction
, il est évident ce que vous devez faire pour l'inclure dans le test.
Ces blocs de macro s'étendent à quelque chose comme ceci:
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;
}
Lequel préférez-vous lire et conserver?
Un autre exemple est dans le cadre Microsoft MFC, où vous mappez des fonctions à des 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( )
Alors, quelles sont les choses qui distinguent les "bonnes macros" des horribles sortes de mal?
Ils effectuent une tâche qui ne peut être simplifiée autrement. L'écriture d'une macro pour déterminer un maximum entre deux éléments est incorrecte, car vous pouvez obtenir la même chose à l'aide d'une méthode de modèle. Mais il existe des tâches complexes (par exemple, mappage des codes de message aux fonctions membres) que le langage C ++ ne gère tout simplement pas avec élégance.
Ils ont un usage formel extrêmement strict. Dans ces deux exemples, les blocs de macro sont annoncés en démarrant et en terminant les macros, et les macros intermédiaires n'apparaissent que dans ces blocs. Vous avez un C ++ normal, vous vous excusez brièvement avec un bloc de macros, puis vous revenez à la normale. Dans les exemples de "macros diaboliques", les macros sont dispersées dans le code et le malheureux lecteur n'a aucun moyen de savoir quand les règles C ++ s'appliquent et quand elles ne le sont pas.