namespace c++ para que sirve
¿Cuál es un escenario de uso apropiado de#define en C++? (5)
Conozco las reglas básicas, use inline
, enum
y const
lugar de #define
, eso no es lo que busco con esta pregunta. Lo que quiero saber es qué se considera un escenario aceptable en el que utilizaría una macro #define
y cómo, en C ++.
Por favor, no publique preguntas o enlaces para "definir vs const" o "preprocesador vs compilador", y ya he revisado Effective C ++ de Scott Meyers y conozco las ventajas de una sobre la otra.
Sin embargo, después de horas y horas de navegar por la red, tengo la sensación de que #define se trata como una especie de perdedor en C ++, pero estoy seguro de que debe haber un caso en el que sea aceptable, incluso deseable, usarlo.
Creo que una de las situaciones en las que puedo pensar es en crear una macro DEBUG
que, con base en ella, permita impresiones y todo lo demás en todo el código para fines de depuración.
A veces, desea generar código sin tener que repetir el interminable repetitivo, o sin tener que usar otro idioma para hacerlo. De vez en cuando , las plantillas no serán suficientes y terminará utilizando el procesador Boost.Preprocessor para generar su código.
Un ejemplo donde las macros son "necesarias" es Boost.TTI (introspección de rasgos de tipo). El mecanismo subyacente de alguna manera abusa del lenguaje para crear un par de poderosas metafunciones, pero necesita grandes cantidades de repetitivo. Por ejemplo, la macro BOOST_TTI_HAS_MEMBER_FUNCTION
genera una función mate que verifica si una clase tiene una función miembro dada. Hacerlo requiere crear una nueva clase y no puede ser corto sin una macro (ejemplos de soluciones que no son macro para resolver el problema here ).
También hay ocasiones en las que necesitarás usar X-macros para generar tu código. Es bastante útil para unir cosas en tiempo de compilación. No estoy seguro de si pueden reemplazarse por completo o no a partir de hoy, pero de todos modos, puede encontrar algunos ejemplos realmente interesantes de aplicaciones here .
En resumen, las macros pueden ser una herramienta poderosa para generar código, pero deben usarse con precaución.
Aquí hay algunos escenarios en los que usar #define es una buena solución:
Agregando información de diagnóstico mientras se conserva la firma de la función:
#ifdef _DEBUG
#define Log(MSG) Log((MSG), __FILE__, __LINE__);
#endif
La compilación condicional y los guardias de inclusión también son un buen ejemplo (no se proporciona ningún ejemplo, como debe entenderse :)).
El código de Boilerplate es otro ejemplo, pero se puede abusar fácilmente. Un buen ejemplo del uso de macros para código repetitivo es la macro BOOST_AUTO_TEST_CASE en Boost.UnitTest (un ejemplo peor es el conjunto de macros WinAPI que asigna las API de Windows a sus macros CHAR o WCHAR).
Otro buen ejemplo es proporcionar configuraciones y palabras clave específicas del compilador:
#if (defined _WIN32) && (defined LIB_SHARED)
# ifdef LIB_EXPORTS
# define LIB_EXPORT __declspec(dllexport)
# else
# define LIB_EXPORT __declspec(dllimport)
# endif /* LIB_EXPORTS */
#else
# define LIB_EXPORT extern
#endif /* _WIN32 && LIB_SHARED */
Uso:
// forward declaration of API function:
LIB_EXPORT void MyFunction(int);
Creo que cuando se introdujo C, C no solía tener consts, por lo que #defines
era la única forma de proporcionar valores constantes. Pero más tarde #define
no se usó mucho ya que consts tomó el lugar ( o mejor dicho podemos decir que los consts se usaron más fácilmente ). Pero yo diría que incluir guardias sigue siendo un área donde se usan. Y se utilizan ya que su código es más legible.
Los guardias de inclusión de encabezados son un área donde no se pueden usar consts
Y ejemplo :
#ifndef GRANDFATHER_H
#define GRANDFATHER_H
struct foo {
int member;
};
#endif /* GRANDFATHER_H */
También puede marcar ¿Por qué alguien usaría #define para definir constantes?
Una cosa más para agregar es que #defines
no respeta los ámbitos, por lo que no hay forma de crear un espacio de clase, ya que las variables const se pueden clasificar en clases ( sé que se sabe la diferencia, pero se piensa que hay que agregarla porque es importante ) .
También para mostrar un ejemplo donde se usa #define:
static double elapsed()
{ ... }
#define ELAPSED ''['' << std::fixed << std::setprecision(2) << elapsed() << "] "
// usage:
for (vector<string>::iterator f = files.begin(); f != files.end(); f++) {
cout << ELAPSED << "reading file: " << *f << ''/n'';
process_file(*f);
}
La configuración simple para depuración / lanzamiento o para código de multiplataforma. Aquí hay una muestra de mi programa:
void Painter::render()
{
if (m_needsSorting)
{
_sort();
}
for (GameObject* o : m_objects)
{
o->render();
#ifdef _DEBUG
o->renderDebug();
#endif
}
}
y uno más para ganar / ios:
#ifdef _WIN32
#include "EGL/egl.h"
#include "GLES2/gl2.h"
#include <Windows.h>
#ifdef _ANALYZE
#include <vld.h>
#endif
#else // IOS
#import <Availability.h>
#import <UIKit/UIKit.h>
#import <GLKit/GLKit.h>
#import <Foundation/Foundation.h>
#endif
Lo otro es para las bibliotecas:
#ifdef VECTRY_INLINE
#define vinline inline
#else
#define vinline
#endif
y algunas cosas útiles como esta:
#define MakeShared(T) /
class T; /
typedef shared_ptr<T> T##Ptr
Uno de los pocos casos útiles en C ++ es incluir guardias:
// A.h
#ifndef _A_H_
#define _A_H_
class A
{ /* ... */ };
#endif /* _A_H_ */