【问题标题】:std::get<0>(...) and enum indexstd::get<0>(...) 和枚举索引
【发布时间】:2019-01-30 15:00:09
【问题描述】:

为了使代码更具可读性,我使用tuple 执行了以下操作:

std::tuple<uint32_t, uint32_t, uint32_t> key;

enum  tpl {
    arg1 = 0, arg2 = 1, arg3 = 2
};

现在我可以写了:

 auto _arg1 = std::get<tpl::arg1>(key);

我现在遇到一个问题。如果我写:

auto arg1 = std::get<tpl::arg1>(key);

变量arg1 已经是枚举。因此我想切换到:

enum class tpl: int {
    arg1 = 0, arg2 = 1, arg3 = 2
};

但是这里有问题。编译器说:

错误 C2672: 'std::get': 找不到匹配的重载函数

std::get 中的这个索引是什么类型,可以在枚举类的定义中命名吗?

我试过了

const constexpr
const int 
....

【问题讨论】:

  • The variable arg1 is already the enum 不清楚。为什么会出现问题?
  • @balki - 枚举标识符是enum 所在范围的成员(不是enum class)。所以这可能会导致冲突,除非引入某种范围。
  • balki:以上名称仅为示例。在实际项目中,有几个变量名称几乎相同。

标签: c++ c++17 stdtuple


【解决方案1】:

作用域枚举 (enum class) 没有隐式转换为任何类型的整数。由于std::get 需要一个整数类型的模板参数,所以必须进行这样的转换。

但它不能,因此没有重载与提供的模板参数匹配。

您可以使用在 C++11 之前采用的“作用域枚举”hack:

struct tpl {
  enum : int {
    arg1 = 0, arg2 = 1, arg3 = 2
  };
};

这使得标识符有范围,但保留了隐式转换。引入了 C++11 范围枚举,因为通常隐式转换不是所需的功能,但在这种情况下,我敢说它是。

【讨论】:

  • 感谢您的解决方案。
【解决方案2】:

问题是作用域枚举不会隐式转换为其基础类型。你可以手动做到这一点

std::get<static_cast<std::underlying_type_t<tpl>>(tpl::arg1)>(key);

但是由于您的尝试是为了提高可读性,因此这不是一个好的解决方案。相反,请考虑以下选项:

namespace tpl {
   enum { arg1 = 0, arg2 = 1, arg3 = 2 };
}

std::get<tpl::arg1>(key);

它不具有与强类型枚举相同的类型安全含义,但它允许您想到的语法调用。

附带说明一下,一旦您担心使用 std::tuple 对象的可读性影响,您可能想改用一个琐碎的 struct

【讨论】:

  • mmm... 所以using namespace tpl; 允许在可能的情况下使用简写。我喜欢它,所以有一个uppy。
  • @StoryTeller 谢谢!有点像穷人版的P1099 :)
  • 是的,你是对的,我可以切换到 struct 但元组中有一些东西。在项目的生命周期中,我可以切换。感谢带有命名空间的灵魂!
【解决方案3】:

std::get 的索引模板参数是std::size_t 类型。范围枚举不能隐式转换为其基础类型。所以如果你坚持使用一个,你必须施放它。

auto arg1 = std::get<static_cast<int>(tpl::arg1)>(key);

如果您想避免在演员表中提及基础类型

auto arg1 = std::get<static_cast<std::underlying_type_t<tpl>>(tpl::arg1)>(key);

【讨论】:

    猜你喜欢
    • 2014-10-26
    • 1970-01-01
    • 1970-01-01
    • 2021-11-21
    • 2011-10-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多