Although I think that think this question will be closed as primarily opinion based, I will offer my opinion.
The main reason that I know of to avoid static constants is that you can run into linker errors if you define them inline and need to take them by reference. See this. Since this isn't an integral type, you would either have to make the class constexpr and define static constants inline(outside of the class) or define them outside of the class in an implementation file. Either way requires an implementation file (the inline constexpr constants version is the one that will cause linker errors).
I would prefer to make such a simple class constexpr and define the predefined colors as static constexpr functions:
struct Color
{
static constexpr Color red() { return Color(255, 0, 0); }
static constexpr Color green() { return Color(0, 255, 0); }
static constexpr Color blue() { return Color(0, 0, 255); }
static constexpr Color black() { return Color(0, 0, 0); }
static constexpr Color white() { return Color(255, 255, 255); }
constexpr Color(uint8_t r, uint8_t g, uint8_t b, uint8_t a = 255)
: r(r), g(g), b(b), a(a)
{}
uint8_t r;
uint8_t g;
uint8_t b;
uint8_t a;
};
void do_something_with_color(const Color& color)
{
printf("worked\n");
}
int main()
{
do_something_with_color(Color::red());
return 0;
}
As a side note, this is one of those times when you really are dealing with a struct. The public interface for the type is its components, so they should be public. This function-based approach has no performance penalty, avoids the possible linker errors, and is more flexible and cleaner in my opinion.