std::get<0>(...) 和枚举索引

std::get<0>(...) and enum index

为了使代码更具可读性,我对 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
};

但这里有些不对劲。编译器说:

error C2672: 'std::get': no matching overloaded function found

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

我试过了

const constexpr
const int 
....

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

作用域枚举 (enum class) 没有到任何类型整数的隐式转换。由于 std::get 需要整数类型的模板参数,因此必须进行这种转换。

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

您可以使用 "scoped enum" 在 C++11 之前使用的 hack:

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

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

问题是作用域枚举没有隐式转换为它们的基础类型。您可以通过

手动执行此操作
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