Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Redefinitions of constexpr static data members are allowed now? (but not inline const)?

Tags:

c++

c++17

c++14

The following fails to compile under both gcc and clang in c++14, but succeeds with c++1z:

struct Cls {
  static constexpr int N = 0;
};
constexpr int Cls::N;
constexpr int Cls::N;

The C++14 error is predictable: redefinition of ‘constexpr const int Cls::N’

What changed to make this legal? I found:

n4659 10.1.5 [dcl.constexpr]

A function or static data member declared with the constexpr specifier is implicitly an inline function or variable

So I thought it might have to do with inline variables, but the following fails for c++1z under both compilers

struct Cls {
  static inline const int N = 0;
};
inline const int Cls::N; // note, only one definition here
like image 329
Ryan Haining Avatar asked Jul 10 '17 19:07

Ryan Haining


People also ask

Can constexpr be inline?

A constexpr function or constructor is implicitly inline . The following rules apply to constexpr functions: A constexpr function must accept and return only literal types. A constexpr function can be recursive.

Why is constexpr over const?

const can only be used with non-static member function whereas constexpr can be used with member and non-member functions, even with constructors but with condition that argument and return type must be of literal types.

Does constexpr need to be static?

A static constexpr variable has to be set at compilation, because its lifetime is the the whole program. Without the static keyword, the compiler isn't bound to set the value at compilation, and could decide to set it later. So, what does constexpr mean?

Is constexpr implicitly const?

In C++11, constexpr member functions are implicitly const.


1 Answers

Before C++17, you needed to re-declare all static variables outside the class in exactly one translation unit (typically each translation unit is a .cpp file and vice versa, but this isn’t required). As you pointed out, C++17 introduces inline class member variables, and static constexpr variables automatically qualify. You are not allowed to redeclare inline variables outside the class, as you saw in your second example, but an exception was made for constexpr because previously you were allowed (and in fact required) to do so, but the syntax is deprecated.

In [class.static.data]p2, it allows that syntax for non-inline members (“The declaration of a non-inline static data member in its class definition is not a definition and may be of an incomplete type other than cv void. The definition for a static data member that is not defined inline in the class definition shall appear in a namespace scope enclosing the member’s class definition.”)

In the next paragraph, the standard allows constexpr outside-of-class declarations and requires them for non-constexpr data (emphasis added):

If a non-volatile non-inline 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 (8.20). The member shall still be defined in a namespace scope if it is odr-used (6.2) in the program and the namespace scope definition shall not contain an initializer. An inline static data member may be defined in the class definition and may specify a brace-or-equal-initializer. If the member is declared with the constexpr specifier, it may be redeclared in namespace scope with no initializer (this usage is deprecated; see D.1). Declarations of other static data members shall not specify a brace-or-equal-initializer.

And here’s the deprecation note, D.1 Redeclaration of static constexpr data members [depr.static_constexpr]:

For compatibility with prior C++ International Standards, a constexpr static data member may be redundantly redeclared outside the class with no initializer. This usage is deprecated. [ Example:

struct A {
  static constexpr int n = 5; // definition (declaration in C++ 2014)
};
constexpr int A::n; // redundant declaration (definition in C++ 2014)

— end example ]

like image 170
Daniel H Avatar answered Sep 17 '22 15:09

Daniel H