Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ static constexpr field with incomplete type

Tags:

c++

c++11

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?

like image 810
lodo Avatar asked Apr 03 '15 12:04

lodo


People also ask

Can a member of an incomplete type be declared in C++?

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.

What is an incomplete 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 ...

What is the constexpr specifier in C++?

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.

What is a constant static member in C++?

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:


2 Answers

Unfortunately, you simply cannot do this!

Some static constexpr members may be initialised inline:

[C++11 9.4.2/3]: [..] 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. [..]

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 a static 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 a static data member shall appear in a namespace scope enclosing the member’s class definition. In the definition at namespace scope, the name of the static data member shall be qualified by its class name using the :: operator. The initializer expression in the definition of a static 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]: A constexpr specifier used in an object declaration declares the object as const. 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.

like image 125
Lightness Races in Orbit Avatar answered Sep 20 '22 17:09

Lightness Races in Orbit


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}; }; 
like image 39
Ben Voigt Avatar answered Sep 17 '22 17:09

Ben Voigt