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

编程入门 行业动态 更新时间:2024-10-27 10:27:41
本文介绍了在类型特征中,为什么人们使用枚举而不是静态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来获取价值?

本文发布于:2023-10-24 06:02:12,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1523122.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:静态   而不是   特征   类型   价值

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!