The rule of thumb here is that you cannot use in-class member initialization of a member variable if it's static
(and not also const int
), however there are some exceptions (just none that apply to your case).
In the C++98 standard, you could only member initialize static const int
In C++11 standard, you can member initialize everything except static
(with exception to the C++98 standard).
You could get around this if your static member was constexpr
:
§ 9.4.2 (November 2014 draft)
If a non-volatile const static data member is of integral or enumeration type, its declaration in the class
definition can specify a brace-or-equal-initializer in which every initializer-clause that is an assignment-expression
is a constant expression (5.20). A static data member of literal type can be declared in the
class definition with the constexpr specifier; if so, its declaration shall specify a brace-or-equal-initializer
in which every initializer-clause that is an assignment-expression is a constant expression. [ Note: In both
these cases, the member may appear in constant expressions. — end note ] The member shall still be defined
in a namespace scope if it is odr-used (3.2) in the program and the namespace scope definition shall not
contain an initializer.
To explain this snippet a little more clearly:
If you want to try to get around things with constexpr
, your type must be "literal".
A literal type (§ 3.9.10):
- Has a "trivial" destructor
- Has only constant expression constructors
- Has only literal type base classes and data members
- Or is an aggregate type
- Or is
void
, scalar (e.g., int
), a reference, or array of literal types
A destructor is "trivial" if:
- It's compiler-generated (i.e. you didn't define one)
- And each non-static member object has a trivial destructor
Given all of this, you might take a look at your code and think "Hm, well I could make all my constructors constexpr
, and then change static const CColorf blue
to static constexpr CColorf blue
and I'm good."
However, your class is "incomplete" at the time you declare your static. Let's think about the following example:
class A{
private:
A member;
}
Every instance of A
now has an instance of A
. How many bytes does the compiler allocate for A
? It can't tell. Infinitely many, perhaps, due to the recursion. A is incomplete inside it's own class. You have a similar problem of incompleteness. However, let's make it a pointer instead:
class A{
private:
A* member;
}
Now it's easy because A*
is a pointer type, which the compiler knows the size of.
So now you think "Okay, I'll just make static constexpr CColorf blue
a pointer like static constexpr CColorf* blue = new CColorf(0.0f, 0.0f, 1.0f);
But you can't, because the new
operator is not constexpr
.
And you can't try const
because we already went over why.
So maybe you think about overloading the new
operator to be constexpr
, but you can't do that either.
So you're out of luck.