Trabajando alrededor de las limitaciones de los miembros de datos estáticos `constexpr` con el mismo tipo que la clase encapsuladora.
Quiero dar capacidades constexpr
a una clase Color
que se ve así:
// color.hpp
struct Color
{
Color(int r, int g, int b, int a);
static const Color Red;
// ...
};
// color.cpp
Color::Color(int r, int g, int b, int a) { /* ... */ }
const Color Color::Red(255, 0, 0, 255);
// ...
Mi deseo es mantener sin cambios la API de esta clase, por lo tanto, me gustaría eliminar por completo color.cpp
y hacer estos cambios en el archivo de encabezado:
// color.hpp
struct Color
{
constexpr Color(int r, int g, int b, int a) { /* ... */ }
inline static constexpr Color Red{255, 0, 0, 255};
// ...
};
Sin embargo, el código anterior no se compila ya que los miembros de datos estáticos constexpr
con el mismo tipo que la clase contenedora no están permitidos en C++.
Por supuesto, podría cambiar la API a algo como ColorConstants::Red
y mover el objeto Red
fuera de la clase, pero no quiero romper a los usuarios existentes.
La única solución alternativa que se me ocurrió se parece a esto:
// color.hpp
struct Color
{
private:
struct ColorInit
{
int r, g, b, a;
constexpr ColorInit(int r, int g, int b, int a) { /* ... */ }
constexpr inline operator Color() const { /* ... */ }
}
public:
constexpr Color(int r, int g, int b, int a) { /* ... */ }
inline static constexpr ColorInit Red{255, 0, 0, 255};
};
La solución alternativa anterior permite que la mayoría del código existente que utiliza Color
se siga compilando después de los cambios, pero obviamente falla cada vez que Red
no se usa en un contexto donde se requiera una conversión implícita a Color
.
Entonces, mi pregunta es: ¿es posible encontrar una solución para evitar la limitación de constexpr
mencionada anteriormente, convirtiendo Red
en una expresión constante, manteniendo al mismo tiempo la sintaxis original Color::Red
y evitando romper el código existente?
davy.ai
A partir de C++17, no es posible tener un miembro de datos estático
constexpr
del mismo tipo que la clase que lo contiene. Por lo tanto, la solución propuesta en la pregunta es una opción para mantener la sintaxis original deColor::Red
mientras se permite queRed
sea una expresión constante.Otra opción podría ser usar una función
constexpr
en lugar de un constructorconstexpr
para crear el objetoRed
dentro de la definición de la clase, de la siguiente manera:Esto permite utilizar
Red
como una expresión constante, a la vez que se conserva la sintaxis original deColor::Red
. Sin embargo, el código existente que utilizaColor::Red
como un miembro de datos estático debería actualizarse para utilizarColor::Red()
en su lugar.En última instancia, la decisión de si utilizar la solución propuesta o actualizar la API depende de los requisitos y restricciones específicas del proyecto.