在C ++ 17中,我们获得了内联变量,并且我假设全局constexpr变量是隐式内联的。 但是很显然,这仅适用于静态成员变量。
这背后的逻辑/技术限制是什么?
来源:
声明为constexpr的静态成员变量(但不是名称空间范围的变量)隐式为内联变量。
答案 0 :(得分:7)
constexpr
被隐式地制作为inline
的静态数据成员的原因是为了解决C ++中的一个常见问题:在定义类范围的常量时,以前不得不将其完全以一个常量发出定义。转换单位,以免变量使用ODR:
// foo.h
struct foo {
static constexpr int kAnswer = 42;
};
// foo.cpp
// a linker error will occur if this definition is omitted before C++17
#include "foo.h"
constexpr int foo::kAnswer;
// main.cpp
#include "foo.h"
#include <vector>
int main() {
std::vector<int> bar;
bar.push_back(foo::kAnswer); // ODR-use of 42
}
在这种情况下,我们通常只关心常量的值,而不关心常量的地址;如果常量确实用于ODR,则编译器可以很方便地为常量合成一个唯一的位置,但是我们不在乎该位置在哪里。
因此,C ++ 17更改了规则,因此不再需要离线定义。为此,它使foo::kAnswer
的声明成为内联定义,以便它可以像内联函数一样出现在多个翻译单元中而不会发生冲突。
对于 namespace-scope constexpr
变量(隐式static
,因此具有内部链接,除非声明为extern
)没有类似的问题。每个翻译单位都有自己的副本。当前指定的inline
对此类变量无效。改变现有行为会破坏现有程序。
答案 1 :(得分:5)
这里的意思是,命名空间范围内的constexpr int x = 1;
在C ++ 14中具有内部链接。
如果隐式内联而不更改内部链接部分,则更改将无效,因为内部链接意味着无论如何都无法在其他翻译单元中对其进行定义。而且这损害了教学能力,因为我们希望像inline constexpr int x = 1;
这样的东西默认获得外部链接(毕竟,内联的全部目的是允许在多个翻译中定义 same 变量单位)。
如果使它隐式地与外部链接内联,则会破坏现有代码:
// TU1
constexpr int x = 1;
// TU2
constexpr int x = 2;
此完全有效的C ++ 14会违反ODR。