Tho*_*mas 19 c++ enums static templates const
例如,这就是我写它的方式,它编译并且工作得很好:
template<typename T> struct is_pointer<T*> {
  static const bool value = true;
}
那么为什么有些人写的不太明显
template<typename T> struct is_pointer<T*> {
  enum { value = true };
}      
代替?是不是因为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);
}
下列不工作,而不是(你会得到一个未定义的引用来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);
}
当然,除非你添加以下几行,否则它不起作用:
template<typename T>
const bool is_pointer<T*>::value;
那是因为[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; }; 
这不起作用,这就是我发现它们之间的微妙差异的方式.
我在这里找到了帮助,因为我得到了一些很好的提示.
参考标准是一个加号,以更好地解释在幕后发生的事情.
请注意,static constexpr像上面那样的数据成员声明也是自C++ 17以来的定义.因此,您不必再定义它,您将能够直接使用它来代替它.
正如评论中提到的那样(感谢@Yakk确认了这一点)我也试图解释上面提到的命名常量如何绑定到const引用.
[expr.const/3]引入了整数常量表达式,并enum通过说它隐式转换为prvalue来提及未编译的s .
[dcl.init.ref/5]和[class.temporary/2]完成剩下的工作,因为他们统治参考绑定和临时.
是不是因为
static const变量使用了一个字节的内存,而enum不是?
是的,这就是原因.
static const bool value = true;
会占据记忆,而
enum { value = true };
没有.
是的你是对的:enum { value = true };不占用任何记忆.
此外,在C++ 11之前,它几乎是实现这一目标的唯一方法:static const bool value = true;仅在C++ 11以后的类定义中是合法的.虽然constexpr可能是首选.