这可能是一个基本问题,但我现在无法看到自己的反应。
请考虑以下代码:
template<bool b>
struct T {
static constexpr int value = (b ? 42 : 0);
};
template<bool b>
struct U {
enum { value = (b ? 42 : 0) };
};
int main() {
static_assert(T<true>::value == 42, "!");
static_assert(T<false>::value == 0, "!");
static_assert(U<true>::value == 42, "!");
static_assert(U<false>::value == 0, "!");
}
我习惯使用像T
这样的结构,但我不止一次看到像U
这样的结构用于同一目的(主要是特征定义)。
据我所知,它们都是在编译时解决的,它们解决了几乎相同的问题,但在我看来,T
比U
更具可读性(好吧,我知道,我的个人意见。)
我的问题非常简单:是否有任何技术原因可以解决一个解决方案比另一个解决方案更好的问题? 更有甚者,其中一个不是一个可行的解决方案吗?
答案 0 :(得分:25)
使用时,积分常数没有明显的差异。
但是,enum
实际上更好,因为它是一个真正的命名常量。 constexpr
整数常量是一个对象,例如,可以使用ODR,这会导致链接错误。
#include <iostream>
struct T {
static constexpr int i = 42;
enum : int {x = 42};
};
void check(const int& z) {
std::cout << "Check: " << z << "\n";
}
int main() {
// check(T::i); // Uncommenting this will lead to link error
check(T::x);
}
取消注释check(T::i)
时,程序无法链接:
/tmp/ccZoETx7.o
:在函数“main
”中:ccc.cpp
:(.text+0x45
):undefined 引用“T::i
”collect2
:错误:ld
返回1
退出状态
然而,真正的enum
始终有效。
答案 1 :(得分:4)
我怀疑它的遗留代码。
enum { value = (b ? 42 : 0) };
是C ++ 03以及C ++ 11中的有效代码。
static constexpr int value = (b ? 42 : 0);
仅在C ++ 11中有效。
更重要的是,是否存在其中一个不可行的解决方案?
两者都是C ++ 11中可行的解决方案。选择使用哪一个取决于团队。这将是一个政策决定的问题。
正如answer by SergeyA所示,enum
是真常数。你不能ODR使用它们。您可以ODR使用constexpr
。根据您的应用需要哪些,您可以决定是使用enum
还是constexpr
。
答案 2 :(得分:0)
currently accepted answer by SergeyA从C ++ 17(Definitions and ODR)开始不再适用。
除以下内容外,每个声明都是一个定义:
- ...
- (不建议使用)静态数据成员的命名空间范围声明,该声明 是在类中使用constexpr说明符定义的
struct S {
static constexpr int x = 42; // implicitly inline, defines S::x
};
constexpr int S::x; // declares S::x, not a redefinition
因此,从C ++ 17开始,我将使用比枚举更具表现力的静态constexpr定义。