我正在尝试实现一个全局变量,该变量可被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
目前,我的代码分为以下文件:
#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;
}
#include <array>
#include "globals.h"
class ClassA {
public:
std::array<int, constants::HEIGHT> m_arrayFixedRGBA;
ClassA();
};
#include "classA.h"
ClassA::ClassA() {
}
#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
被#include到不同的代码文件中时,这些变量中的每一个都会被复制到包含的代码文件中。因此,如果globals.h
被包含在20个不同的代码文件中,则每个变量将重复20次。标头防护不会阻止这种情况的发生,因为它们只会阻止标头被多次包含在一个包含文件中,而不是被一次性包含在多个不同的代码文件中。变量的重复并不是真正的问题(因为常量不太可能很大),但是更改单个常量值还需要重新编译每个包含常量头的文件,这可能会导致较长的重建时间用于大型项目。
在这种情况下,有什么解决方法?
答案 0 :(得分:1)
您可以将常量定义为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-use这些常量,则将出现链接时错误,因为链接器无法找到定义。例如,以下代码将失败
std::cout << constants::width << std::endl;
因为operator(std::ostream&, something const&)
通过引用获取要写入的对象。您可以通过在某处(在源文件中)提供定义或避免使用这种方式来避免这种情况,例如
std::cout << int(constants::width) << std::endl;