Esta pregunta ofrece un claro ejemplo de cómo puede usar mal las macros. Para ver otros ejemplos (y entretenerse) vea esta pregunta .
Dicho esto, daré ejemplos del mundo real de lo que considero una buena incorporación de macros.
El primer ejemplo aparece en CppUnit , que es un marco de prueba de unidad. Al igual que cualquier otro marco de prueba estándar, crea una clase de prueba y luego tiene que especificar de alguna manera qué métodos deben ejecutarse como parte de la prueba.
#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();
}
Como puede ver, la clase tiene un bloque de macros como primer elemento. Si agregué un nuevo método testSubtraction
, es obvio lo que debe hacer para incluirlo en la ejecución de la prueba.
Estos macrobloques se expanden a algo como esto:
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;
}
¿Cuál preferirías leer y mantener?
Otro ejemplo está en el marco Microsoft MFC, donde asigna funciones a mensajes:
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( )
Entonces, ¿cuáles son las cosas que distinguen a las "buenas macros" del horrible tipo maligno?
Realizan una tarea que no se puede simplificar de otra manera. Escribir una macro para determinar un máximo entre dos elementos es incorrecto, porque puede lograr lo mismo utilizando un método de plantilla. Pero hay algunas tareas complejas (por ejemplo, mapear códigos de mensajes a funciones miembro) que el lenguaje C ++ simplemente no maneja con elegancia.
Tienen un uso extremadamente estricto y formal. En ambos ejemplos, los macrobloques se anuncian al iniciar y finalizar las macros, y las macros intermedias solo aparecerán dentro de estos bloques. Tiene C ++ normal, se disculpa brevemente con un bloque de macros y luego vuelve a la normalidad nuevamente. En los ejemplos de "macros malvadas", las macros están dispersas por todo el código y el desafortunado lector no tiene forma de saber cuándo se aplican las reglas de C ++ y cuándo no.