在类型特征中,为什么人们使用枚举而不是静态const来获取价值? [英] In a type trait, why do people use enum rather than static const for the value?

查看:155
本文介绍了在类型特征中,为什么人们使用枚举而不是静态const来获取价值?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

例如,这是我如何编写它,它编译和工作正常:

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

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

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

代替?这只是因为 static const 变量使用一个字节的内存,而枚举不是? >

解决方案

一个显着的区别在于以下代码编译和链接:

 模板<类型名> 
struct is_pointer {};

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

void f(const bool& b){}

int main(){
f(is_pointer< void *> :: value);
}

以下内容不起作用(您获得了一个未定义的引用到):

  template< typename> 
struct is_pointer {};

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

void f(const bool& b){}

int main(){
f(is_pointer< void *> :: value);
}

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

 模板< typename T> 
const bool is_pointer< T *> :: value;

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


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


其他术语 static const bool value = true; 是一个声明,而不是一个定义,你不能odr使用

另一方面,根据 [dcl.enum / 1] (强调我的):


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


这些命名的常量可以被引用,如上面的例子所示。






作为附注,如果您使用 static constexpr C ++ 11/14中的数据成员:

 模板< ; typename T> 
struct is_pointer< T *> {static constexpr bool value = true; };

这不起作用,这就是我发现它们之间微妙的区别。 >

我在这里找到帮助,因此我得到了一些很好的提示。

参考标准是一个加号,以更好地解释什么是请注意, static constexpr 数据成员声明如上所述也是自C ++ 17以来的定义。因此,您不必再定义它,您可以直接使用它。






如评论中所提到的(感谢@Yakk证实了这一点),我也试图解释如何发生,上面提到的命名常量绑定到一个const引用。



[expr.const / 3] 引入整数常量表达式,并提及未限定的枚举,表示将其隐式转换为 prvalue

[dcl.init.ref / 5] [class.temporary / 2] 做其他事情,因为他们统治参考约束和临时性。


For example, this is how I would write it, and it compiles and works just fine:

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

Then why do some people write the less obvious

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

instead? Is it only because the static const variable uses a byte of memory, whereas the enum doesn't?

解决方案

A notable difference is in the fact that the following code compiles and links:

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);
}

The following does not work instead (you get an undefined reference to 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);
}

Of course, it doesn't work unless you add somewhere the following lines:

template<typename T>
const bool is_pointer<T*>::value;

That is because of [class.static.data]/3 (emphasis mine):

If a non-volatile non-inline const static data member is of integral or enumeration type, its declaration in the class definition can specify a brace-or-equal-initializer in which every initializer-clause that is an assignment-expression is a constant expression ([expr.const]). The member shall still be defined in a namespace scope if it is odr-used ([basic.def.odr]) in the program and the namespace scope definition shall not contain an initializer. [...]

In other terms, static const bool value = true; is a declaration, not a definition and you cannot odr-use value.
On the other side, according with [dcl.enum/1] (emphasis mine):

An enumeration is a distinct type with named constants.

Those named constants can be const referenced as shown in the example above.


As a side note, something similar applies if you use static constexpr data members in C++11/14:

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

This doesn't work as well and that's how I discovered the subtle differences between them.

I found help here on SO getting some nice hints out of the answer I've been given.
References to the standard are a plus to better explain what's going on under the hood.

Note that a static constexpr data member declaration like the one above is also a definition since C++17. Therefore you won't have to define it anymore and you'll be able to odr-use it directly instead.


As mentioned in the comments (thanks to @Yakk that confirmed this) I'm also trying to explain how it happens that the above mentioned named constants bind to a const reference.

[expr.const/3] introduces the integral constant expression and mentions unscoped enums by saying that it's implicitly converted to a prvalue.
[dcl.init.ref/5] and [class.temporary/2] do the rest, for they rule on reference binding and temporaries.

这篇关于在类型特征中,为什么人们使用枚举而不是静态const来获取价值?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆