【问题标题】:Use Enum or #define?使用枚举还是#define?
【发布时间】:2010-03-30 20:32:41
【问题描述】:

我正在构建一个玩具解释器,并且我已经实现了一个包含令牌类型和值的令牌类。

token类型一般是整数,但是int应该怎么抽象呢?

什么是更好的主意:

// #defines
#define T_NEWLINE 1
#define T_STRING 2
#define T_BLAH 3

/**
 * Or...
 */

// enum
enum TokenTypes
{
   t_newline = 1,
   t_string = 2,
   t_blah = 3
};

【问题讨论】:

标签: c++


【解决方案1】:

枚举可以转换为整数;此外,它们是枚举 C++ 中预定义值列表的首选方式。与#defines 不同,它们可以放在命名空间、类等中。

另外,如果你需要第一个索引以1开头,你可以使用:

enum TokenTypes
{
   t_newline = 1,
   t_string,
   t_blah
};

【讨论】:

  • 而当我使用枚举时,如何使用构造函数设置令牌类型?使用定义并不难:Token myToken(T_NEWLINE);,但是我如何使用枚举来做到这一点?
  • 如果你想要一个token类型作为一个类的成员变量,你可以声明一个变量TokenTypes myval;并且在构造函数的初始化列表中,你会拥有myval(t_newline)
  • C++ 枚举也比 #defines 更安全。
【解决方案2】:

枚举在调试器中工作(例如,说“print x”将打印“English”值)。 #defines 没有(即您只剩下数字,并且必须自己参考源来进行映射)。

因此,使用枚举。

【讨论】:

    【解决方案3】:

    这里有多种解决方案。

    首先,使用#define 指的是过去的C。在C++ 中,这通常被认为是不好的做法,因为以这种方式定义的符号不遵守作用域规则,而是被不执行任何语法检查的预处理器替换...导致难以理解的错误。

    其他解决方案是关于创建全局常量。净好处是它们不会被预处理器解释,而是由编译器解释,因此遵守语法检查和范围规则。

    创建全局常量的方法有很多:

    // ints
    const int T_NEWLINE = 1;
    
    struct Tokens { static const int T_FOO = 2; };
    
    // enums
    enum { T_BAR = 3; }; // anonymous enum
    
    enum Token { T_BLAH = 4; }; // named enum
    
    // Strong Typing
    BOOST_STRONG_TYPEDEF(int, Token);
    const Token NewLine = 1;
    const Token Foo = 2;
    
    // Other Strong Typing
    class Token
    {
    public:
      static const Token NewLine; // defined to Token("NewLine")
      static const Token Foo;     // defined to Token("Foo")
    
      bool operator<(Token rhs) const { return mValue < rhs.mValue; }
      bool operator==(Token rhs) const { return mValue == rhs.mValue; }
      bool operator!=(Token rhs) const { return mValue != rhs.mValue; }
    
      friend std::string toString(Token t) { return t.mValue; } // for printing
    
    private:
      explicit Token(const char* value);
    
      const char* mValue;
    };
    

    每个人都有自己的长处和短处。

    • int 缺乏类型安全性,您可以轻松地在需要使用另一类常量的地方使用一类常量
    • enum 支持自动递增,但你没有漂亮的打印,而且它仍然不是那么安全(即使更好一点)。
    • StrongTypedef 我更喜欢enum。你可以回int
    • 创建自己的类是最好的选择,例如,在这里您可以打印出漂亮的消息,但这也需要更多的工作(不多,但仍然如此)。

    此外,intenum 方法生成的代码可能与 #define 方法一样高效:编译器会尽可能用 const 值替换它们的实际值。

    【讨论】:

    • mValue 应该是 std::string?或者使用 std::strcmp 作为 mValue 成员上的比较运算符。
    【解决方案4】:

    在您所描述的情况下,我更喜欢使用枚举,因为它们更容易维护。特别是,如果数字表示没有任何特定含义。

    【讨论】:

    • 使用枚举,那么如何在构造函数中设置令牌类型呢?例如令牌 myToken( 类型 );
    • 您所要做的就是:Token myToken(t_string)
    【解决方案5】:

    枚举是类型安全的,更容易阅读,更容易调试,并且得到了智能感知的良好支持。我会说尽可能使用 Enum,并在必要时使用#define。

    请参阅有关 C/C++ 中 const 与 define 的相关讨论,我对这篇文章的回答还列出了您何时必须使用 #define 预处理器。

    Shall I prefer constants over defines?

    【讨论】:

      【解决方案6】:

      我投票给枚举

      #define 不是类型安全的,如果你不小心可以重新定义。

      【讨论】:

        【解决方案7】:

        枚举的另一个原因:它们是作用域的,所以如果标签 t_blah 存在于另一个命名空间(例如另一个类)中,它不会干扰 t_blah 在您当前的命名空间(或类),即使它们具有不同的 int 表示形式。

        【讨论】:

          【解决方案8】:

          enum 提供类型安全、可读性和调试器。如前所述,它们非常重要。

          枚举提供的另一件事是可能性的集合。例如

          enum color
          {
            red,
            green,
            blue,
            unknown
          };
          

          我认为#define(或const)是不可能的

          【讨论】:

            【解决方案9】:

            好的,已经发布了很多答案,所以我会想出一些不同的东西:C++0x strong typed enumerators :)

            enum class Color /* Note the "class" */
            {
               Red,
               Blue,
               Yellow
            };
            

            与旧枚举的特点、优势和区别

            • 类型安全int color = Color::Red; 将是编译时错误。您必须使用 Color color 或将 Red 转换为 int。
            • 更改基础类型:您可以更改其基础类型(许多编译器也在 C++98 中提供扩展来执行此操作):enum class Color : unsigned short。 unsigned short 将是类型。
            • 显式作用域(我最喜欢的):在上面的示例中,Red 将是未定义的;你必须使用Color::Red。想象一下新的枚举也是一种命名空间,所以它们不会用可能是通用名称(“red”、“valid”、“invalid”等)污染您当前的命名空间。
            • 前向声明enum class Color; 告诉编译器Color 是一个枚举,您可以开始使用它(当然不是值);有点像class Test;,然后使用Test *

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2023-04-10
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2010-09-27
              相关资源
              最近更新 更多