I'm trying to compile this code, but g++ complains about ZERO
having an incomplete type. Does this mean that in C++ a struct cannot contain a static constexpr
instance of itself? If so, why?
struct Cursor { size_t row,column; static constexpr Cursor ZERO {0,0}; //error: constexpr const Cursor Cursor::ZERO has incomplete type };
EDIT: I understand that Cursor
cannot have a complete type when I declare ZERO
. What I'd like to know is: is there any way I can have ZERO
belonging to Cursor
and still being constexpr
?
The declaration inside the class body is not a definition and may declare the member to be of incomplete type (other than void ), including the type in which the member is declared: However, if the declaration uses constexpr or inline (since C++17) specifier, the member must be declared to have complete type.
An incomplete type can be: 1 A structure type whose members you have not yet specified. 2 A union type whose members you have not yet specified. 3 An array type whose dimension you have not yet specified. More ...
The constexpr specifier declares that it is possible to evaluate the value of the function or variable at compile time. Such variables and functions can then be used where only compile time constant expressions are allowed.
Constant static members. If a static data member of integral or enumeration type is declared const (and not volatile), it can be initialized with an initializer in which every expression is a constant expression, right inside the class definition:
Unfortunately, you simply cannot do this!
Some static constexpr
members may be initialised inline:
[C++11 9.4.2/3]:
[..] Astatic
data member of literal type can be declared in the class definition with theconstexpr
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. [..]
Cursor
is a literal type, so this counts.
And the use of Cursor
itself as a static
data member within its own type is not a problem, as long as you initialise it at lexical namespace scope:
[C++11: 9.4.2/2]:
The declaration of astatic
data member in its class definition is not a definition and may be of an incomplete type other than cv-qualified void. The definition for astatic
data member shall appear in a namespace scope enclosing the member’s class definition. In the definition at namespace scope, the name of thestatic
data member shall be qualified by its class name using the::
operator. The initializer expression in the definition of astatic
data member is in the scope of its class (3.3.7).
But you can't do that with constexpr
:
[C++11: 7.1.5/9]:
Aconstexpr
specifier used in an object declaration declares the object asconst
. Such an object shall have literal type and shall be initialized. [..]
I think all of this wording could be improved but, in the meantime, I think you're going to have to make ZERO
a non-member in the enclosing namespace.
is there any way I can have ZERO belonging to Cursor and still being
constexpr
?
Yes, if you count nested subclasses as "belonging to" the containing class:
struct Cursor { size_t row,column; struct Constants; }; struct Cursor::Constants { static constexpr Cursor ZERO {0,0}; };
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