在类型特征中,为什么人们使用枚举而不是静态const作为值?

Tho*_*mas 19 c++ enums static templates const

例如,这就是我写它的方式,它编译并且工作得很好:

template<typename T> struct is_pointer<T*> {
  static const bool value = true;
}
Run Code Online (Sandbox Code Playgroud)

那么为什么有些人写的不太明显

template<typename T> struct is_pointer<T*> {
  enum { value = true };
}      
Run Code Online (Sandbox Code Playgroud)

代替?是不是因为static const变量使用了一个字节的内存,而enum不是?

sky*_*ack 23

一个值得注意的区别在于以下代码编译和链接:

template<typename>
struct is_pointer { };

template<typename T>  
struct is_pointer<T*> {
  enum { value = true };
};     

void f(const bool &b) { }

int main() {
  f(is_pointer<void*>::value);
}
Run Code Online (Sandbox Code Playgroud)

下列不工作,而不是(你会得到一个未定义的引用value):

template<typename>
struct is_pointer { };

template<typename T>
struct is_pointer<T*> {
  static const bool value = true;
};

void f(const bool &b) { }

int main() {
  f(is_pointer<void*>::value);
}
Run Code Online (Sandbox Code Playgroud)

当然,除非你添加以下几行,否则它不起作用:

template<typename T>
const bool is_pointer<T*>::value;
Run Code Online (Sandbox Code Playgroud)

那是因为[class.static.data]/3(强调我的):

如果非易失性非内联const静态数据成员是整数或枚举类型,则它在类定义中的声明可以指定一个大括号或大小为初始化器,其中作为赋值表达式的每个initializer子句都是一个常量表达式([expr.const]).如果程序中的odr-used([basic.def.odr])并且命名空间作用域定义不包含初始化程序,则仍应在名称空间作用域中定义该成员.[...]

换句话说,static const bool value = true;是一个声明,而不是一个定义,你不能使用odr value.
另一方面,根据[dcl.enum/1](强调我的):

枚举是具有命名常量的不同类型.

那些命名常量可以被const引用,如上例所示.


作为旁注,如果您static constexpr在C++ 11/14中使用数据成员,则类似的情况也适用:

template<typename T>
struct is_pointer<T*> { static constexpr bool value = true; }; 
Run Code Online (Sandbox Code Playgroud)

这不起作用,这就是我发现它们之间的微妙差异的方式.

我在这里找到了帮助,因为我得到了一些很好的提示.
参考标准是一个加号,以更好地解释在幕后发生的事情.

请注意,static constexpr像上面那样的数据成员声明也是自C++ 17以来的定义.因此,您不必再定义它,您将能够直接使用它来代替它.


正如评论中提到的那样(感谢@Yakk确认了这一点)我也试图解释上面提到的命名常量如何绑定到const引用.

[expr.const/3]引入了整数常量表达式,enum通过说它隐式转换为prvalue来提及未编译的s .
[dcl.init.ref/5][class.temporary/2]完成剩下的工作,因为他们统治参考绑定和临时.

  • Upvoted.OP应该接受这个答案来取代我的. (2认同)
  • @Thomas:`静态`数据成员确实只存在于内存中,如果它们被定义,如果它们的地址被采用(通过指针或引用)则需要它.当它节省内存时很棒,当链接器抱怨你忘记定义*叹息*时会很烦人. (2认同)

πάν*_*ῥεῖ 6

是不是因为static const变量使用了一个字节的内存,而enum不是?

是的,这就是原因.

static const bool value = true;
Run Code Online (Sandbox Code Playgroud)

会占据记忆,而

enum { value = true };
Run Code Online (Sandbox Code Playgroud)

没有.

  • @skypjack很好的推理.我赞成你的回答. (3认同)
  • `static const bool value = true;`,在类定义中,不占用任何内存.内存将被相应的类外定义占用,但只有在`value`为*odr-used*时才需要. (3认同)
  • 不幸的是(?)并不是唯一一个比另一个更好的原因.;-) (2认同)

Bat*_*eba 6

是的你是对的:enum { value = true };不占用任何记忆.

此外,在C++ 11之前,它几乎是实现这一目标的唯一方法:static const bool value = true;仅在C++ 11以后的类定义中是合法的.虽然constexpr可能是首选.

  • 不幸的是(?)并不是唯一一个比另一个更好的原因.;-) (2认同)