【问题标题】:Is there a way to specify an enum-class value without having to type out its scope every time?有没有办法指定一个枚举类值而不必每次都输入它的范围?
【发布时间】:2018-11-21 15:18:17
【问题描述】:

我有一些函数可以返回成功或一组固定的错误代码。为了识别错误代码,我(类似于)声明了这个老式 C 风格的枚举:

enum {
   RESULT_ERROR_BAD_PARAMETER = -3,
   RESULT_ERROR_FILE_NOT_FOUND = -2,
   RESULT_ERROR_GENERAL = -1,
   RESULT_SUCCESS = 0
};
typedef int my_status_t;

my_status_t MyFunc();   // returns a RESULT_* value

这很好用;调用模式类似于:

if (MyFunc() != RESULT_SUCCESS) printf("Error!\n");

...但是,允许将 my_status_t 值隐式转换为 int/bool/etc 是令人不安的,允许出现这样的粗心错误:

// Compiles but does the wrong thing at run-time -- bad!
if (MyFunc() == false) printf("Error!\n");

...所以在我的新代码修订版中,我将其转换为 enum class

enum class my_status_t {
   RESULT_ERROR_BAD_PARAMETER = -3,
   RESULT_ERROR_FILE_NOT_FOUND = -2,
   RESULT_ERROR_GENERAL = -1,
   RESULT_SUCCESS = 0
};

...从编译时检查的角度来看,这很有效;现在大多数无意的类型提升都被编译器捕获,迫使程序员返回并以正确的方式进行。

唯一困扰我的是新语法很乏味:现在我必须写这样的东西:

if (MyFunc() != my_status_t::RESULT_SUCCESS) printf("Error!\n");

... 在每个呼叫站点 - 每次都必须输入 my_status_t:: 很乏味,并且使代码更难阅读,并且没有真正增加太多价值(因为 RESULT_SUCCESS 就我的目的而言已经足够独特了,无论如何)

我的问题是,是否有某种using namespace my_status_t; 样式指令可以用来告诉编译器将枚举值导出到它们的my_status_t 命名空间中,这样我就可以引用它们而无需键入@一直都是987654332@前缀?

【问题讨论】:

    标签: c++ c++11 enums namespaces


    【解决方案1】:

    如果你要输入比这里更多的令人讨厌的范围前缀 是enum class 中的常量,那么可能值得您花点时间来使用它 方式:

    enum class result {
       ERROR_BAD_PARAMETER = -3,
       ERROR_FILE_NOT_FOUND = -2,
       ERROR_GENERAL = -1,
       SUCCESS = 0
    };
    
    constexpr result RESULT_ERROR_BAD_PARAMETER = result::ERROR_BAD_PARAMETER;
    constexpr result RESULT_FILE_NOT_FOUND = result::ERROR_FILE_NOT_FOUND;
    constexpr result RESULT_ERROR_GENERAL = result::ERROR_GENERAL;
    constexpr result RESULT_SUCCESS = result::SUCCESS;
    
    result foo() {
        return RESULT_SUCCESS;
    }
    
    int main()
    {
        switch (foo())
        {
            case RESULT_SUCCESS:
                ;
        }
        // ^ warning: enumeration value ‘...’ not handled in ...
    
        if (foo() == RESULT_SUCCESS) {
            return 0;
        }
    
        /* error: no match for ‘operator==’
        if (foo() == false) {
            return -1;
        }
        */
    }
    

    (g++ -Wall -Wextra -pedantic -std=c++11)

    【讨论】:

      【解决方案2】:

      做这个改变:

      enum class result {
        ERROR_BAD_PARAMETER = -3,
        ERROR_FILE_NOT_FOUND = -2,
        ERROR_GENERAL = -1,
        SUCCESS = 0
      };
      

      因为你的枚举值在一个范围内,你不再需要给它们一个名字。

      现在你的代码变成了:

      if (MyFunc() != result::SUCCESS) printf("Error!\n");
      

      比以前长了整整 1 个字符。

      你也可以

      using my_status_t = result;
      

      如果您绑定到 my_status_t 作为类型名称。


      从 C++17 开始,无法完全避免使用 result:: 前缀。在更高版本的 C++ 中有关于 using ERROR_BAD_PARAMETER = result::ERROR_BAD_PARAMETER; 之类的讨论,但我不知道他们是否会进入

      【讨论】:

      • 我正在寻找的是避免something::前缀的能力。
      【解决方案3】:

      这是一种方法:

      enum class my_status_t { };
      
      inline constexpr my_status_t RESULT_ERROR_BAD_PARAMETER = my_status_t(-3);
      // add other enum values here
      

      不幸的是,这样你会失去enum 的一些好的属性。如果您不处理开关中的值,编译器会警告您(如果您的值很大,请不要忘记设置enum class 的基础类型)。

      所以我其实不推荐这种方式(我更喜欢 Yakk 的解决方案),但也许这个答案无论如何都可以帮助你......

      【讨论】:

        猜你喜欢
        • 2011-03-24
        • 1970-01-01
        • 2017-12-05
        • 1970-01-01
        • 1970-01-01
        • 2015-03-17
        • 1970-01-01
        • 1970-01-01
        • 2017-12-08
        相关资源
        最近更新 更多