我想在类的定义中初始化我的私有(private)静态成员“pi”,以便更好地整理我的代码,以便在 .cpp 文件中进行初始化。
当我尝试时,出现此错误:“声明 constexpr 静态数据成员 'pi' 需要初始化程序”
我使用的是 CLion 2018.3.4 和 C++ 11。
我尝试解决,唯一的解决方案是在声明中初始化成员。
Stack Overflow 上的其他答案为我提供了更好的知识,但没有回答我的问题。
//.h文件
class Shape {
public:
virtual void getArea();
private:
static constexpr float pi; // the error shows up here
};
//.cpp 文件
#include "Shape.h"
const float Shape::pi = 3.14; //here I don't exactly know why it does not require constexpr, but it's fine even with and without const
// what I think this is equivalent to (in .h file)
static constexpr float pi = 3.14;
我期望它能像我在声明中分配“3.14”一样工作。
我没有定义构造函数,在这种情况下我知道它不会工作,因为 c'tor 旨在初始化类的实例,而静态成员应该已经初始化为全局元素“Shape”命名空间。
我认为发生的情况是链接器尝试初始化 header 中的成员,因为它必须在预处理阶段完成,而稍后使用 .cpp 文件。
最佳答案
对于static constexpr
成员,您不能在类定义中省略初始值设定项。 constexpr 变量必须在声明时初始化,因为它可以在常量表达式中声明后使用。这在[class.static.data]/3中有详细介绍。 C++11 标准
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 ([expr.const]). 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 ([basic.def.odr]) in the program and the namespace scope definition shall not contain an initializer.
强调我的
因此,您的代码需要是
// .h file
class Shape {
public:
virtual void getArea();
private:
static constexpr float pi = 3.14; // we initialize here so it can be used.
};
// .cpp file
constexpr float Shape::pi; // we define here so it can be odr-used
请注意,这在 C++17 中已发生变化。随着介绍inline variables static constexpr
成员变量不再需要在类外部定义。编译器将为您处理它并确保仅存在该对象的单个定义。如果需要,您仍然可以定义成员,但该功能已弃用,并且很可能会在未来的标准修订版中删除。 [class.static.data]/3 的新文本是
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 ([expr.const]). The member shall still be defined in a namespace scope if it is odr-used ([basic.def.odr]) 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 [depr.static.constexpr]). Declarations of other static data members shall not specify a brace-or-equal-initializer.
强调我的
和[dcl.constexpr]/1表示 static constexpr
变量是隐式内联的
The constexpr specifier shall be applied only to the definition of a variable or variable template or the declaration of a function or function template. The consteval specifier shall be applied only to the declaration of a function or function template. A function or static data member declared with the constexpr or consteval specifier is implicitly an inline function or variable ([dcl.inline]). If any declaration of a function or function template has a constexpr or consteval specifier, then all its declarations shall contain the same specifier.
强调我的
关于c++ - 在定义(.cpp 文件)中初始化 static float constexpr 成员是否可能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57059159/