with macro language how functions elif define c++ c-preprocessor

c++ - language - Pasando la persona que llama__FILE____LINE__ a una función sin usar macro



macro function in c (2)

Estoy acostumbrado a esto:

class Db { _Commit(char *file, int line) { Log("Commit called from %s:%d", file, line); } }; #define Commit() _Commit(__FILE__, __LINE__)

pero el gran problema es que redefino la palabra Commit globalmente, y en un marco de aplicación de 400k líneas es un problema. Y no quiero usar una palabra específica como DbCommit : no me gustan las redundancias como db->DbCommit() , o pasar los valores manualmente en todas partes: db->Commit(__FILE__, __LINE__) es peor.

Entonces, ¿algún consejo?


Entonces, estás buscando hacer un registro (o algo) con información de archivos y líneas, y preferirías no usar macros, ¿verdad?

Al final del día, simplemente no se puede hacer en C ++. Independientemente del mecanismo que elija, ya sea que se trate de funciones en línea, plantillas, parámetros predeterminados u otra cosa, si no usa una macro, simplemente terminará con el nombre de archivo y el número de lino de la función de registro, en lugar de el punto de llamada.

Utilizar macros. Este es un lugar donde realmente no son reemplazables.

EDITAR:

Incluso las preguntas frecuentes de C ++ dicen que las macros son a veces el menor de dos males.

EDIT2:

Como dice Nathon en los comentarios a continuación, en los casos en que usas macros, es mejor ser explícito al respecto. Asigne a sus macros nombres de macro-y, como COMMIT() lugar de Commit() . Esto dejará en claro a los mantenedores y depuradores que hay una macro llamada en curso, y debería ayudar en la mayoría de los casos para evitar colisiones. Ambas cosas buenas.


Puede usar una combinación de parámetros predeterminados y truco del preprocesador para pasar el archivo de la persona que llama a una función. Es el siguiente:

  1. Declaración de función:

    static const char *db_caller_file = CALLER_FILE; class Db { _Commit(const char *file = db_caller_file) { Log("Commit called from %s", file); } };

  2. Declare la variable db_caller_file en el archivo de encabezado de clase. Cada unidad de traducción tendrá un const char *db_caller_file . Es estático, por lo que no interferirá entre las unidades de traducción. (No hay declaraciones múltiples).

  3. Ahora lo que es CALLER_FILE , es una macro y se generará a partir de los parámetros de la línea de comando de gcc. En realidad, si se usa el sistema Make automático, donde existe una regla genérica para los archivos de origen, es mucho más fácil: puede agregar una regla para definir la macro con el nombre del archivo como un valor. Por ejemplo:

    CFLAGS= -MMD -MF $(DEPS_DIR)/$<.d -Wall -D''CALLER_FILE="$<"''

-D define una macro, antes de compilar este archivo. $< es la sustitución de Make por el nombre del requisito previo para la regla, que en este caso es el nombre del archivo fuente. Entonces, cada unidad de traducción tendrá su propia variable db_caller_file con valor una cadena, que contiene el nombre del archivo.

No se puede aplicar la misma idea a la línea de la persona que llama, porque cada llamada en la misma unidad de traducción debe tener diferentes números de línea.