c++ - 在 C++ 中使用静态常量成员初始化另一个静态常量

标签 c++ static constants

我面临以下问题:

我有一个 Color 类,为了这个问题的目的,它被简化为:

// Color.h
struct Color {
    int r,g,b;
    Color() : r(0), g(0), b(0) {}
    Color(int r_, int g_, int b_) : r(r_), g(g_), b(b_) {}
    static const Color Red;
    static const Color Magenta;
};

// Color.cpp
#include "Color.h"
const Color Color::Red (255,0,0);
const Color Color::Magenta (255,0,255);

即,我想将类名用作某些预定义颜色的范围。

现在在全局范围内的用户文件中我这样做:

//user.cpp
#include "Color.h"
static const Color colors[2] = { Color::Red, Color::Magenta };

当我使用 colors[i] 时,我看到它们填充了 0。 我查了一下,发现首先调用了空构造函数(这没有意义,原因很快就会揭示),然后我将空构造函数更改为:

    Color() : r(200), g(200), b(200) {}

得到了同样的结果。

我试着像这样将颜色定义为 constexpr :

    static constexpr Color Red (255, 0, 0);

但是它说: 数字常量之前的预期标识符

然后像这样:

    static constexpr Color Red = {255, 0, 0};

像这样:

    static constexpr Color Red = Color(255, 0, 0);

但随后编译失败,因为“'Color' 未在此范围内声明”,以及“Red 的类型不完整”(真的吗?) 所以现在使用空 c'tor 真的没有意义,而是将整个内存初始化为 0。

在运行时我可以使用 static const Colors 并且它有效。

我对这种行为有明确的定义吗?是否取决于编译/链接顺序?

我该如何解决?

谢谢

最佳答案

您正在遇到 Static Initialization Order Fiasco .听起来你的 colors 数组在 RedMagenta 对象之前被初始化。

一个解决方案是 Construct On First Use Idiom :

// Color.h
struct Color {
    int r,g,b;
    Color() : r(0), g(0), b(0) {}
    Color(int r_, int g_, int b_) : r(r_), g(g_), b(b_) {}
    static const Color& Red();
    static const Color& Magenta();
};

// Color.cpp
#include "Color.h"
const Color& Color::Red()
{ static const Color red(255,0,0); return red; }
const Color& Color::Magenta()
{ static const Color magenta(255,0,255); return magenta; }

//user.cpp
#include "Color.h"
static const Color colors[2] = { Color::Red(), Color::Magenta() };

关于c++ - 在 C++ 中使用静态常量成员初始化另一个静态常量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44229029/

相关文章:

C++11 std::conditional 在运行时?

java - 从静态上下文中调用非静态方法

c++ - 如何通过const对象中的指针使对象成为常量?

c++ - 使用非常量变量作为 constexpr 数组的索引来传递给模板参数

c++ - Qt emit 需要 30 毫秒,这可能吗?

c++ - 在头文件中使用enable_if对模板进行特化

java - 在静态 block 中初始化线程?

c++ - 常量类成员不是常量 - C++

c++ - 尝试初始化动态数组时未处理异常

Java的final方法使用静态绑定(bind),但JVM在编译时使用 "invokevirtual"指令