要定义整数类型的编译时常量,如下所示(在函数和类范围内),哪种语法最好?
static const int kMagic = 64; // (1)
constexpr int kMagic = 64; // (2)
Run Code Online (Sandbox Code Playgroud)
(1)也适用于C++ 98/03编译器,而(2)至少需要C++ 11.这两者之间还有其他差异吗?在现代C++代码中是否应该首选其中一个,为什么?
编辑
我用Godbolt的CE尝试了这个示例代码:
int main()
{
#define USE_STATIC_CONST
#ifdef USE_STATIC_CONST
static const int kOk = 0;
static const int kError = 1;
#else
constexpr int kOk = 0;
constexpr int kError = 1;
#endif
return kOk;
}
Run Code Online (Sandbox Code Playgroud)
对于这种static const情况,这是GCC 6.2生成的程序集:
main::kOk:
.zero 4
main::kError:
.long 1
main:
push rbp
mov rbp, …Run Code Online (Sandbox Code Playgroud) 我是否违反了One Definition Rule并使用以下程序?
// foo.hpp
#ifndef FOO_HPP_
#define FOO_HPP_
namespace {
inline int foo() {
return 1;
}
}
inline int bar() {
return foo();
}
#endif
//EOF
Run Code Online (Sandbox Code Playgroud)
和
// m1.cpp
#include "foo.hpp"
int m1() {
return bar();
}
//EOF
Run Code Online (Sandbox Code Playgroud)
和
// m2.cpp
#include "foo.hpp"
int m2() {
return bar();
}
//EOF
Run Code Online (Sandbox Code Playgroud)
最后
// main.cpp
#include <iostream>
int m1();
int m2();
int main(int, const char* [])
{
int i = m1();
int j = m2();
std::cout << (i+j) << std::endl; …Run Code Online (Sandbox Code Playgroud) 考虑以下标题并假设它在多个TU中使用:
static int x = 0;
struct A {
A() {
++x;
printf("%d\n", x);
}
};
Run Code Online (Sandbox Code Playgroud)
正如这个问题所解释的那样,这是ODR违规,因此也就是UB.
现在,如果我们的函数引用非对象并且我们不在该函数中使用它(加上其他条款),则不存在ODR违规,因此这在头文件中仍然可以正常工作:inlinevolatile const
constexpr int x = 1;
struct A {
A() {
printf("%d\n", x);
}
};
Run Code Online (Sandbox Code Playgroud)
但如果我们确实碰巧使用它,我们又回到UB的第一个方面:
constexpr int x = 1;
struct A {
A() {
printf("%p\n", &x);
}
};
Run Code Online (Sandbox Code Playgroud)
因此,鉴于我们现在有inline变量,指南是否应该在标题中标记所有namespace变量inline以避免所有问题?
constexpr inline int x = 1;
struct A {
A() {
printf("%p\n", &x);
}
};
Run Code Online (Sandbox Code Playgroud)
这似乎也更容易教,因为我们可以简单地说" inline标题中的所有内容"(即函数和变量定义),以及"从不static …