如何为 std::array 声明全局编译时常量?

How can I declare a global compile-time constant for std::array?

本文关键字:编译 常量 全局 array std 声明      更新时间:2023-10-16

>我正在尝试实现一个全局变量,该变量将被不同的文件使用,同时与std::array一起使用,但是我收到以下编译器错误:

error: the value of ‘constants::HEIGHT’ is not usable in a constant expression
note: ‘constants::HEIGHT’ was not initialized with a constant expression

我的代码目前被拆分为以下文件:

主.cpp

#include <iostream>
#include "classA.h"
#include "globals.h"
namespace constants {
extern const int WIDTH = 800;
extern const int HEIGHT = 600;
}

int main()
{
ClassA classA;
printf("Hello World");
std::cout << constants::WIDTH << " " << constants::HEIGHT << std::endl;
return 0;
}

类A.h

#include <array>
#include "globals.h"
class ClassA {
public:
std::array<int, constants::HEIGHT> m_arrayFixedRGBA;
ClassA();
};

A类.cpp

#include "classA.h"
ClassA::ClassA() {
}

全局.h

#ifndef CONSTANTS_H
#define CONSTANTS_H
namespace constants {
extern const int WIDTH;
extern const int HEIGHT;
}
#endif

我知道通过删除extern,像这样声明globals.h

#ifndef CONSTANTS_H
#define CONSTANTS_H
namespace constants {
const int WIDTH = 800;
const int HEIGHT = 600;
}
#endif

并删除main.cpp中的相关行,然后程序就可以编译了

虽然这很简单(对于较小的程序来说很好),但每次globals.h#included 到不同的代码文件中时,这些变量中的每一个都会复制到包含代码文件中。因此,如果globals.h被包含在 20 个不同的代码文件中,则每个变量都会重复 20 次。标头保护不会阻止这种情况的发生,因为它们只会防止标头多次包含在单个包含文件中,而不是一次包含在多个不同的代码文件中。这种变量的重复并不是什么大问题(因为常量不太可能很大),但是更改单个常量值还需要重新编译包含常量标头的每个文件,这可能会导致大型项目的重建时间过长。

这种情况的解决方法是什么?

您可以将常量定义为static constexpr成员

// in some header file:
struct constants {
constexpr static int width  = 800;
constexpr static int height = 600;
};

并像使用它们一样使用

std::array<int, constants::height> arr;

------编辑------

请注意,此方法仅声明这些编译时常量,但不定义任何变量。因此,多个定义混淆链接器没有问题(就像使用extern变量的实现一样)。

但是,在 C++17 之前,可能会出现相反的问题:如果 odr 使用这些常量,则会出现链接时错误,因为链接器找不到定义。例如,以下代码将失败

std::cout << constants::width << std::endl;

因为operator(std::ostream&, something const&)通过引用来获取要写入的对象。您可以通过在某处(在源文件中)提供定义或避免此类使用来避免这种情况,例如

std::cout << int(constants::width) << std::endl;