【问题标题】:generic int -> enum conversion with templates possible?可以使用模板进行通用 int-> 枚举转换吗?
【发布时间】:2016-06-25 15:45:51
【问题描述】:

我使用这样的函数将 int(来自旧版 API)转换为 enum

TestEnum to_test_enum(int value) {
    TestEnum converted(static_cast<TestEnum>(value));
#   pragma GCC diagnostic push
#   pragma GCC diagnostic error "-Wswitch"
    switch (converted) {
        case TestEnum::A:
        case TestEnum::B:
            return converted;
    }
#   pragma GCC diagnostic pop

    throw std::runtime_error("wrong value");
}

to_test_enum 如果向to_enum 传递了无效值,则抛出异常,否则返回相应的TestEnum 值。 pragma 确保在缺少合法值的情况下会出现编译器错误。

像这样的行现在将转换一个整数并在运行时进行有效性检查:

enum class TestEnum {
    A = 1,
    B = 2,
};

auto v1 = to_test_enum(2);
auto v2 = to_test_enum(3);  // will throw

问题:我想知道是否可以通过某种模板魔法将其变成函数模板:

template<class E>
E to_enum(int value) {
    E converted(static_cast<E>(value));
    switch (converted) {
        EACH ELEMENT e IN E: case e:   <--- here goes some unrolling magic
            return converted;
    }

    throw std::runtime_error("wrong value");
}

然后将像这样使用该函数:

auto v1 = to_enum<TestEnum>(2);
auto v2 = to_enum<TestEnum>(3);  // will throw

【问题讨论】:

  • 不,(除非你做了一些诡计的事情来通过一些自省来声明枚举)。
  • 如果您添加 First 和 Last 或其他占位符元素来表示可能的范围,那么这可能是可能的,但是这会强制枚举值覆盖连续的值范围而没有任何漏洞,不确定如果你想这样做。
  • 我发现了一些有用的预处理器魔法,它可以从同一个文本文件创建几个相关的 C++ 事物(例如,创建一个映射 enum -> enumNameString,定义 enumType_first 和 enumType_last,并可能定义一个内联转换函数)。
  • This answer (免责声明:作者)描述了一些你可以做的声明技巧来实现这一点。它没有显示from_int 函数,但希望一旦您可以进行声明,就可以清楚地了解如何实现它。需要注意的一点是,您可以实现的明显转换需要与枚举数成线性关系的时间。

标签: c++ templates enums casting int


【解决方案1】:

我不确定我是否理解您要执行的操作。看下面的一个想法。您必须定义自己的 map_enum&lt; your_enum &gt;() 才能将整数映射到枚举。

#include <map>
#include <iostream>

template< typename E > const std::map< int, E >& map_enum()
{
  return 0;
}

template < typename E > E to_enum( int ai )
{
  auto m = map_enum< E >();
  auto const i = m.find( ai );
  return i == m.end() ? throw -1 : i->second;
}

// { old api
#define RED 0
#define GREEN 1
#define BLUE 2

int old_api_fun()
{
  return 2;
}
// } old api

// { your code
enum color_e
{
  red = RED,
  green = GREEN,
  blue = BLUE
};

template<> const std::map< int, color_e >& map_enum()
{
  static std::map< int, color_e > m ={ { RED, red }, { GREEN, green }, { BLUE, blue } };
  return m;
}
// } your code

int main()
{
  try
  {
    auto r = to_enum< color_e >( old_api_fun() );
    std::cout << "success";
  }
  catch ( int )
  {
    std::cout << "failed";
  }
  return 0;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-07-04
    • 1970-01-01
    • 2013-06-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多