简体   繁体   English

可以在定义(.cpp文件)中初始化静态float constexpr成员

[英]Initialize static float constexpr member in the definition (.cpp file) is it possible

I would like to initialize my private static member "pi" in the definition of the class in order to tidy my code better having the initializations in the .cpp files. 我想在类的定义中初始化我的私有静态成员“ pi”,以使代码更整洁,以便在.cpp文件中进行初始化。

When I try this error shows up: "Declaration of constexpr static data member 'pi' requires an initializer" 当我尝试此错误时出现:“ constexpr静态数据成员'pi'的声明需要初始化程序”

I'm using CLion 2018.3.4 and C++ 11. 我正在使用CLion 2018.3.4和C ++ 11。

I tried to work around and the only solution is to initialize the member in the declaration. 我试图解决,唯一的解决方案是初始化声明中的成员。

Other answers on Stack Overflow provided me a better knowledge but didn't answer my question. 关于Stack Overflow的其他答案为我提供了更好的知识,但没有回答我的问题。

// .h file // .h文件

class Shape {
public:
    virtual void getArea();

private:
    static constexpr float pi; // the error shows up here
};

// .cpp file // .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;

I was expecting this to work like I was assigning "3.14" in the declaration. 我期望它能像在声明中分配“ 3.14”一样工作。

I'm not defining a constructor, in that case I know it wouldn't work because the c'tor is meant to initialize an instance of the class while a static member is supposed to be already initialized being a global element in the "Shape" namespace. 我没有定义构造函数,在那种情况下,我知道它是行不通的,因为c'tor旨在初始化类的实例,而静态成员应该已经初始化为“ Shape”中的全局​​元素”名称空间。

What I suppose it is happening is that the linker tries to initialize the member in the header because it has to be done in the pre-processing phase while the .cpp file is used later. 我想这是因为链接器试图在标头中初始化成员,因为它必须在预处理阶段完成,而以后要使用.cpp文件。

With static constexpr members you cannot leave off the initializer in the class definition. 使用static constexpr成员,您不能在类定义中放弃初始化程序。 A constexpr variable must be initialized when declared because it can be used after it is declared in a constant expression. constexpr变量在声明时必须初始化,因为可以在常量表达式中声明它后使用它。 This is detailed in [class.static.data]/3 of the C++11 standard C ++ 11标准的[class.static.data] / 3中对此进行了详细说明

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]). 如果非易失性const静态数据成员是整数或枚举类型,则其在类定义中的声明可以指定大括号或相等初始化器,其中每个作为赋值表达式的初始化子句都是一个常量表达式([ expr.const])。 A static data member of literal type can be declared in the class definition with the constexpr specifier; 可以使用constexpr说明符在类定义中声明文字类型的静态数据成员; 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. — [end note] 如果在程序中对成员进行了odr-use([basic.def.odr]),则该成员仍应在命名空间范围中定义,并且命名空间范围定义不应包含初始化程序。

emphasis mine 重点矿

So, with that, your code needs to be 因此,您的代码需要

// .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

Do note that this has changed in C++17. 请注意,这在C ++ 17中已更改。 With the introduction of inline variables static constexpr member variables no longer need to be defined outside of the class. 随着内联变量的引入,不再需要在类外部定义static constexpr成员变量。 The compiler will handle it for you and ensure only a single defentition of the object exists. 编译器将为您处理该问题,并确保仅存在单个对象定义。 You can still define the member if you want, but that ability is deprecated and will most likely be removed in a future standard revision. 如果需要,您仍然可以定义成员,但是该功能已被弃用,并且很可能在将来的标准修订版中删除。 The new text for [class.static.data]/3 is [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]). 如果非易失性非内联const静态数据成员是整数或枚举类型,则其在类定义中的声明可以指定大括号或相等初始化器,其中每个作为赋值表达式的初始化子句都是常量表达式([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. 如果在程序中对成员进行了odr-used([basic.def.odr]),则该成员仍应在命名空间范围内定义,并且命名空间范围定义不应包含初始化程序。 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]). 如果使用constexpr说明符声明了该成员,则可以在没有初始化程序的命名空间范围内对其进行重新声明(不建议使用此用法;请参见[depr.static.constexpr])。 Declarations of other static data members shall not specify a brace-or-equal-initializer. 其他静态数据成员的声明不应指定大括号或相等的初始化程序。

emphasis mine 重点矿

and [dcl.constexpr]/1 says that a static constexpr variable is implicitly inline 并且[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. constexpr说明符应仅应用于变量或变量模板的定义或函数或函数模板的声明。 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]) . 用constexpr或consteval说明符声明的函数或静态数据成员隐式是内联函数或变量([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. 如果函数或函数模板的任何声明具有constexpr或consteval说明符,则其所有声明应包含相同的说明符。

emphasis mine 重点矿

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM