【问题标题】:How to restrict conversion from int to enum class?如何限制从 int 到 enum 类的转换?
【发布时间】:2019-11-06 06:07:19
【问题描述】:

如果我有这样的enum class

enum class Weekday {
  Monday,
  Tuesday,
  Wednesday,
  Thursday,
  Friday,
  Saturday,
  Sunday
}

我有一个从intWeekday 的转换:

Weekday day = static_cast<int>(value);

要检查为转换提供的值是否有效,我应该有代码:

if (value != 0 && value != 1 && value !=2 && value !=3 && value != 4 && value != 5 && value != 6) { 
  do_conversion(value); 
}

太丑了。有什么好办法吗?

【问题讨论】:

  • 您可以分配第一个项目= 0并添加最后一个项目LAST左右,然后可以像for (int i = 0; i &lt; LAST; i++)一样循环它们
  • 不是重点,但如果不是可接受的值则转换?
  • ...或者只是for (int i = 0; i &lt;= Sunday; i++)
  • 为什么 do_conversion() 被调用为无效的 value?这就是重点,@user4581301 也注意到了这一点。
  • @user4581301 很想看到这个答案! ^^

标签: c++ c++11 coding-style


【解决方案1】:

这在表面上可能过于复杂,但它很好地概括了模板 voodoo 可以隐藏在远离视线的标题中。

#include <stdexcept>
template <class TYPE>
TYPE do_conversion(int value)
{
    if (value >= static_cast<int>(TYPE::First) &&
        value < static_cast<int>(TYPE::Last))
    {
        return static_cast<TYPE>(value);
    }
    throw std::out_of_range("Inv value");
}

所有的转换都被转移到一个函数中以降低噪音。 有效范围使用额外的枚举值First and Last 进行抽象。如果给定值在范围内(FirstLast],则分配该值。如果不是,则抛出异常。根据无效输入的频率,异常可能不是正确的做法,如果错误的输入很常见,但在这里它有助于使示例保持简单。

现在调用很简单

enum class Weekday
{
    Monday,
    Tuesday,
    Wednesday,
    Thursday,
    Friday,
    Saturday,
    Sunday,
    Last,           // added
    First = Monday  // added
};

以后

Weekday day = do_conversion<Weekday>(value);

转换产生的所有噪音都不会影响转换所需的任何内容,因此读取或编写该段代码的任何人都可以继续他们的工作。

但是如果你在没有FirstLastenum 上使用它呢?编译器消息可能会变得奇怪,因此最好帮助用户一点。以下内容已从How to detect whether there is a specific member variable in class? 中掠夺,以使其更易于使用。绝对花时间阅读答案以了解发生了什么。我还没有想出一个体面的方法来结合HasFirstHasLast。请发表评论,如果你有,请告诉我。

#include <stdexcept>
#include <type_traits>
template <typename T, typename = int>
struct HasFirst : std::false_type { };

template <typename T>
struct HasFirst <T, decltype((void) T::First, 0)> : std::true_type { };

template <typename T, typename = int>
struct HasLast : std::false_type { };

template <typename T>
struct HasLast <T, decltype((void) T::Last, 0)> : std::true_type { };

template <class TYPE>
TYPE do_conversion(int value)
{
    static_assert(HasFirst<TYPE>::value, "enum missing First");
    static_assert(HasLast<TYPE>::value, "enum missing Last");
    if (value >= static_cast<int>(TYPE::First) &&
        value < static_cast<int>(TYPE::Last))
    {
        return static_cast<TYPE>(value);
    }
    throw std::out_of_range("Inv value");
}

现在,如果 enum 缺少最重要的元值,编译器可以通过简单的错误消息告诉它们。

Test case

【讨论】:

  • 你甚至可以使用底层类型。
【解决方案2】:

枚举类的默认基础类型是整数。因此,要检查一个整数是否在可接受的枚举值范围内,您可以使用static_cast&lt;int&gt; 将其与可接受的枚举值范围进行比较:

if (value >= static_cast<int>(Weekday::Monday) && value <= static_cast<int>(Weekday::Sunday))
{
    do_conversion(value);
}

【讨论】:

    猜你喜欢
    • 2017-08-25
    • 2010-10-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-22
    • 2016-02-05
    • 2014-07-20
    • 1970-01-01
    相关资源
    最近更新 更多