C ++ 17更新:static constexpr
变量隐式为inline
,因此不需要外部定义。
原始问题:
假设我有一个常量列表,例如
struct Cls {
static constexpr int N = 32;
static constexpr int M = 64;
};
这当然表明我为这些添加定义以避免可能发生的ODR使用问题,因此我需要:
constexpr int Cls::N;
constexpr int Cls::M;
为什么我更喜欢这个
struct Cls {
enum : int {
N = 32,
M = 64
};
};
这节省了ODR使用的麻烦,因为N
和M
更真实地只是常量而不是它们自己的对象(如果这只是标题,那就更大了)并且更短。如果需要,我可以明确指定类型enum : long long
或其他任何东西。第一个有什么优势?
一个区别是你可以采取static constexpr
但不是enum
的地址。
另一个原因是旧版本的语言不支持constexpr
(它是在C ++ 11中引入的)。
只有当值组合在一起时才使用enum
。我还给enum
一个描述这种关系的名字。我不会使用enum
来定义不相关的常量。
您的使用可能没有任何优势,因为您只是使用简单的固定整数值。
但是,[AFAIK] constexpr
可以更通用,因为它允许从编译时可以评估的任何内容进行初始化。
来自type_traits
:
/// integral_constant template<typename _Tp, _Tp __v> struct integral_constant { static constexpr _Tp value = __v; typedef _Tp value_type; typedef integral_constant<_Tp, __v> type; constexpr operator value_type() const { return value; } #if __cplusplus > 201103L #define __cpp_lib_integral_constant_callable 201304 constexpr value_type operator()() const { return value; } #endif };
因此,constexpr
可用于元编程。
以下是有点粗糙。
如果你有一个像这样的功能:
constexpr unsigned
bitmask(int bitno)
{
return 1u << bitno;
}
您可能会发现以下用法:
constexpr unsigned BIT_0 = bitmask(0);
constexpr unsigned BIT_1 = bitmask(1);
我很确定我会为此受到抨击,但......
我给你的原因是使用enum { }
作为常量是对enum
一词的误用。你没有列举任何东西。这是一种常见的误用,被授予;它有其实际优势;但这只是一种错误。应该有一种方法可以说“这只是一个编译时常量而不是其他”。 constexpr也不是那个,但它比枚举更接近。而且你无法枚举浮点值。
话虽这么说 - 当我想保护自己免受人们写void* ptr = &some_constant_value; std::cout << ptr;
之类的东西时,我经常自己使用枚举作为常量