This is what I have now:
class CColorf
{
public:
CColorf();
CColorf(float r, float g, float b, float a = 1.0f);
public:
float r, g, b, a;
// predefined colors
// rgb(0.0, 0.0, 1.0)
static const CColorf blue;
};
It works with blue
defined in ccolorf.cpp like so:
CColorf const CColorf::blue = CColorf(0.0f, 0.0f, 1.0f);
And this is what I would like to do:
class CColorf
{
...
// predefined colors
// rgb(0.0, 0.0, 1.0)
static const CColorf blue = CColorf(0.0f, 0.0f, 1.0f);
};
But it produces a compilation error:
a static data member with an in-class initializer must have non-volatile const integral type
Is there a way to avoid the need for separate declaration and definition here?
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):
void
, scalar (e.g., int
), a reference, or array of literal typesA destructor is "trivial" if:
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.
You can't do that.
The error message implies that you're compiling as C++03, where only constant static members of integral type can be initialised in their declaration; so you can't do this for any class type.
C++11 relaxes the rules, but there are still restrictions:
constexpr
; butWhile the first point can be fixed, and the third would just restrict what you can do with the member, not whether you can define it, the second makes it impossible. You'll have to define the variable in the usual way, outside the class in a single translation unit.
If you want to keep everything in the class definition, and the value available to help compile-time optimisation, you could define a function rather than a variable
static CColorf blue() {return CColorf(0.0f, 0.0f, 1.0f);}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With