草庐IT

c++ - 我能否始终安全地转换为固定(作用域)枚举的基础类型?

coder 2023-11-14 原文

TL;DR:以下总是安全的吗?还是会导致未定义、未指定或实现定义的行为?

template <class T> 
using ut = typename std::underlying_type<T>::type;

template <typename E> ut<E> identity(ut<E> value) {
  return static_cast<ut<E>>(static_cast<E>(value));
}

如果我有一个作用域枚举,我总是可以将它转换为底层类型:

#include <cassert>             // if you want to follow along
#include <initializer_list>    // copy everything and remove my text

enum class priority : int { 
  low = 0, 
  normal = 1,
  high = 2 
};

// works fine
int example = static_cast<int>(priority::high);

对于枚举中定义的所有值,我也可以期望我得到值:

constexpr priority identity_witness(priority p) {
  return static_cast<priority>(static_cast<int>(p));
}

void test_enum() {
  for (const auto p : {priority::low, priority::normal, priority::high}) {
    assert(p == identity_witness(p));
  }
}

根据 N3337 (C++11),5.2.9 静态转换 [expr.static.cast] § 9-10 这很好:

  1. A value of a scoped enumeration type (7.2) can be explicitly converted to an integral type. The value is unchanged if the original value can be represented by the specified type. …
  2. A value of integral or enumeration type can be explicitly converted to an enumeration type. The value is unchanged if the original value is within the range of the enumeration values (7.2). …

但是,我对反过来感兴趣。如果我强制转换为枚举并返回基础类型会怎样?

constexpr int identity_witness(int i) {
  return static_cast<int>(static_cast<priority>(i));
}

void test_int() {
  for (const auto p : {0, 1, 2, 3, 4, 5}) {
    assert(p == identity_witness(p));
  }
}

int main() {
  test_enum();
  test_int();
}

这可以编译并且工作正常,因为 static_cast底层类型根本不会改变内存(可能)。但是,标准表示,如果值不在范围内,则行为未指定:

  1. [continued] Otherwise, the resulting value is unspecified (and might not be in that range).

我不清楚枚举的范围。根据 7.2§7,如果枚举的基础类型是固定的,“枚举的值是基础类型的值”。因此,对于任何 std::underlying_type<my_enumeration_type> ,上面的性质应该成立。

这个论点是否成立,或者我是否遗漏了标准中的一些奇怪条款,以便强制转换为枚举的基础类型可能会导致未定义或未指定的行为?

最佳答案

该标准似乎决定允许您使用给定类型的任意整数值作为固定为该类型的枚举的值,即使它们没有被命名为枚举值。 5.2.9.10 中的警告大概是为了限制没有固定基础类型的枚举。该标准没有将固定类型枚举值的“范围”定义为与枚举值分开的任何内容。特别是,它说:

It is possible to define an enumeration that has values not defined by any of its enumerators.

所以“在枚举值的范围内”不能理解为“是枚举值之一”之外的任何东西。枚举值的范围没有其他定义。

因此,您可以安全地使用具有固定基础类型的枚举。对于无类型枚举,只有坚持安全的位数才是安全的。

关于c++ - 我能否始终安全地转换为固定(作用域)枚举的基础类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45484581/

有关c++ - 我能否始终安全地转换为固定(作用域)枚举的基础类型?的更多相关文章

  1. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  2. ruby-on-rails - 如果 Object::try 被发送到一个 nil 对象,为什么它会起作用? - 2

    如果您尝试在Ruby中的nil对象上调用方法,则会出现NoMethodError异常并显示消息:"undefinedmethod‘...’fornil:NilClass"然而,有一个tryRails中的方法,如果它被发送到一个nil对象,它只返回nil:require'rubygems'require'active_support/all'nil.try(:nonexisting_method)#noNoMethodErrorexceptionanymore那么try如何在内部工作以防止该异常? 最佳答案 像Ruby中的所有其他对象

  3. ruby - 如何安全地删除文件? - 2

    在Ruby中是否有Gem或安全删除文件的方法?我想避免系统上可能不存在的外部程序。“安全删除”指的是覆盖文件内容。 最佳答案 如果您使用的是*nix,一个很好的方法是使用exec/open3/open4调用shred:`shred-fxuz#{filename}`http://www.gnu.org/s/coreutils/manual/html_node/shred-invocation.html检查这个类似的帖子:Writingafileshredderinpythonorruby?

  4. ruby - 使用 `+=` 和 `send` 方法 - 2

    如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是:

  5. postman接口测试工具-基础使用教程 - 2

    1.postman介绍Postman一款非常流行的API调试工具。其实,开发人员用的更多。因为测试人员做接口测试会有更多选择,例如Jmeter、soapUI等。不过,对于开发过程中去调试接口,Postman确实足够的简单方便,而且功能强大。2.下载安装官网地址:https://www.postman.com/下载完成后双击安装吧,安装过程极其简单,无需任何操作3.使用教程这里以百度为例,工具使用简单,填写URL地址即可发送请求,在下方查看响应结果和响应状态码常用方法都有支持请求方法:getpostputdeleteGet、Post、Put与Delete的作用get:请求方法一般是用于数据查询,

  6. 软件测试基础 - 2

    Ⅰ软件测试基础一、软件测试基础理论1、软件测试的必要性所有的产品或者服务上线都需要测试2、测试的发展过程3、什么是软件测试找bug,发现缺陷4、测试的定义使用人工或自动的手段来运行或者测试某个系统的过程。目的在于检测它是否满足规定的需求。弄清预期结果和实际结果的差别。5、测试的目的以最小的人力、物力和时间找出软件中潜在的错误和缺陷6、测试的原则28原则:20%的主要功能要重点测(eg:支付宝的支付功能,其他功能都是次要的)80%的错误存在于20%的代码中7、测试标准8、测试的基本要求功能测试性能测试安全性测试兼容性测试易用性测试外观界面测试可靠性测试二、质量模型衡量一个优秀软件的维度①功能性功

  7. ES基础入门 - 2

    ES一、简介1、ElasticStackES技术栈:ElasticSearch:存数据+搜索;QL;Kibana:Web可视化平台,分析。LogStash:日志收集,Log4j:产生日志;log.info(xxx)。。。。使用场景:metrics:指标监控…2、基本概念Index(索引)动词:保存(插入)名词:类似MySQL数据库,给数据Type(类型)已废弃,以前类似MySQL的表现在用索引对数据分类Document(文档)真正要保存的一个JSON数据{name:"tcx"}二、入门实战{"name":"DESKTOP-1TSVGKG","cluster_name":"elasticsear

  8. ruby - 如何计算 Liquid 中的变量 +1 - 2

    我对如何计算通过{%assignvar=0%}赋值的变量加一完全感到困惑。这应该是最简单的任务。到目前为止,这是我尝试过的:{%assignamount=0%}{%forvariantinproduct.variants%}{%assignamount=amount+1%}{%endfor%}Amount:{{amount}}结果总是0。也许我忽略了一些明显的东西。也许有更好的方法。我想要存档的只是获取运行的迭代次数。 最佳答案 因为{{incrementamount}}将输出您的变量值并且不会影响{%assign%}定义的变量,我

  9. ruby - 在 Ruby 中将整数格式化为固定长度的字符串 - 2

    有没有一种简单的方法可以将给定的整数格式化为具有固定长度和前导零的字符串?#convertnumberstostringsoffixedlength3[1,12,123,1234].map{|e|???}=>["001","012","123","234"]我找到了解决方案,但也许还有更聪明的方法。format('%03d',e)[-3..-1] 最佳答案 如何使用%1000而不是进行字符串操作来获取最后三位数字?[1,12,123,1234].map{|e|format('%03d',e%1000)}更新:根据theTinMan的

  10. ruby-on-rails - "assigns"在 Ruby on Rails 中有什么作用? - 2

    我目前正在尝试学习RubyonRails和测试框架RSpec。assigns在此RSpec测试中做什么?describe"GETindex"doit"assignsallmymodelas@mymodel"domymodel=Factory(:mymodel)get:indexassigns(:mymodels).shouldeq([mymodel])endend 最佳答案 assigns只是检查您在Controller中设置的实例变量的值。这里检查@mymodels。 关于ruby-o

随机推荐