I want to give constexpr
capabilities to a Color
class that looks like this:
// 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);
// ...
My desire is to keep the API of this class unchanged, therefore I'd like to completely remove color.cpp
and make these changes to the header file:
// color.hpp
struct Color
{
constexpr Color(int r, int g, int b, int a) { /* ... */ }
inline static constexpr Color Red{255, 0, 0, 255};
// ...
};
However, the code above does not compile as constexpr
static data members with the same type as the enclosing class are not allowed in C++.
Of course, I could change the API to something like ColorConstants::Red
and move the Red
object out of the class, but I do not want to break existing users.
The only workaround I've thought of looks like this:
// 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};
};
The above workaround allows most existing code that uses Color
to still compile after the changes, but it obviously fails whenever the Red
is not used in a context where an implicit conversion to Color
is required.
So, my question is: is it possible to work around the constexpr
limitation seen above, turning Red
into a constant expression, while still retaining the original Color::Red
syntax and avoiding breaking existing code?