c++ - name - evitando la redefinición de variables para encabezado único
meta name keywords (2)
Tengo un único requisito de encabezado en un código, lo que significa que no debe haber división de declaraciones y definiciones en encabezado y archivos fuente separados. Lo he implementado correctamente y funciona según lo previsto para mi caso de uso, donde este archivo de encabezado debía incluirse en un único archivo fuente.
Ahora, en lo que se refiere a su uso en múltiples archivos fuente (donde más de un .cpp lo incluye), fallará con el error del enlazador a lo largo de las líneas que algunas variables están siendo redeclaradas. Eso es porque tengo el código como ...
#ifndef HEADER_HPP
#define HEADER_HPP
....
std::streambuf const *R_coutbuf = std::cout.rdbuf();
std::streambuf const *R_cerrbuf = std::cerr.rdbuf();
std::streambuf const *R_clogbuf = std::clog.rdbuf();
void doSomething(){
[uses if(R_coutbuf) and others]
}
....
#endif HEADER_HPP
Ahora la mejor solución sería declarar esos vars en el archivo de encabezado y definirlos / asignarlos en un único archivo cpp, pero como dije, quiero poder hacer esto con un único archivo de encabezado. Lo que trae el problema de que si varios archivos fuente lo incluirán, habrá redeclaraciones.
Hasta ahora no estoy seguro de cómo podría hacerlo, pero tengo dos ideas:
#ifdef DEFINE_VARIABLES
#define EXTERN /* nothing */
#else
#define EXTERN extern int
#endif /* DEFINE_VARIABLES */
EXTERN global_variable = something;
No estoy tan seguro, ¿esto funcionaría?
Y la segunda forma en que pensé es ponerlo en un espacio de nombres anónimo, estoy probando este y hasta ahora está construyendo con éxito -
#ifndef HEADER_HPP
#define HEADER_HPP
....
namespace R {
namespace {
std::streambuf const *R_coutbuf = std::cout.rdbuf();
std::streambuf const *R_cerrbuf = std::cerr.rdbuf();
std::streambuf const *R_clogbuf = std::clog.rdbuf();
}
void doSomething(){
[uses if(R_coutbuf) and others]
}
}
....
#endif HEADER_HPP
¿Hay alguna otra forma en que pueda lograr esto? ¿Hay algún problema con cualquiera de las formas que describí anteriormente?
¿Hay algún problema con cualquiera de las formas que describí anteriormente?
Truco macro
- pros
- Produce una cantidad mínima de variables en los archivos de objeto. Ver la estafa del espacio de nombre anónimo.
- contras
- Muy frágil. Al incluir el encabezado, un programador debe saber si alguna de las otras fuentes existentes incluye las definiciones de las variables. Esto no se escala bien cuando la cantidad de archivos fuente aumenta
Enlace interno (espacio de nombre anónimo)
- pros
- No tiene la desventaja del macro truco.
- contras
- Cada archivo de objeto que incluye el encabezado tendrá su propia copia de las variables. No estoy seguro, pero las variables son
const
y todas tendrán el mismo valor en tiempo de ejecución, el enlazador puede deshacerse de los duplicados. En cualquier caso, la diferencia es solo unos pocos bytes para su programa. Modificar las variables individuales en lugar de modificar una variable compartida cambiaría el significado del programa.
- Cada archivo de objeto que incluye el encabezado tendrá su propia copia de las variables. No estoy seguro, pero las variables son
Para la comparación, consideremos la opción de archivo fuente separado, que ha descartado.
- pros
- Produce una cantidad mínima de variables en los archivos de objeto, como el truco de macro.
- No tiene la desventaja del macro truco.
- contras
- Ninguno (a menos que considere tener un archivo de código fuente separado por sí mismo).
¿Hay alguna otra forma en que pueda lograr esto?
Realmente no. Puede usar palabras clave static
lugar de espacios de nombres anónimos para declarar enlaces internos.
PD. Si define funciones que no sean de plantilla en el encabezado, deben declararse en línea. Su ejemplo anónimo del espacio de nombres no puede hacer esto.
Puede hacer que su variable sea una variable estática local en una función:
inline std::streambuf const*& R_coutbuf() {
static std::streambuf const* b = std::cout.rdbuf();
return b;
}