【问题标题】:Is there a correct way to avoid warnings when comparing two different enums?比较两个不同的枚举时是否有正确的方法来避免警告?
【发布时间】:2009-01-28 05:23:27
【问题描述】:

当比较来自不同来源的枚举时,例如以下代码中的枚举,GCC 会发出警告。有没有办法在没有 c 样式转换的情况下避免这些警告?

struct Enumerator
{
    enum { VALUE = 5 };
};

template<int V>
struct TemplatedEnumerator
{
    enum { VALUE = V };
};

if(Enumerator::VALUE == TemplatedEnumerator<5>::VALUE)
{
  ...
}

GCC 会发出以下类型的警告:

GCC: warning: comparison between 'enum ...' and 'enum ...'

【问题讨论】:

  • 我相信你会被演员卡住。
  • struct Enumerator : boost::integral_constant {};甚至 struct Enumerator : mpl::int_ {};比枚举恕我直言。 c++1x 也将有integral_constant => 你未来是安全的。然后你就可以比较不同类型的 ::value 了。
  • 不幸的是,由于项目提升的政策是禁止的:(

标签: c++ templates gcc enums


【解决方案1】:

我相信您可以提供自己的比较运算符,但您必须先命名枚举:

struct Enumerator
{
    enum Values { VALUE = 5 };
};

template<int V>
struct TemplatedEnumerator
{
    enum Values { VALUE = V };
};


template <int V>
bool operator==(Enumerator::Values lhs, typename TemplatedEnumerator<V>::Values rhs)
{
    return static_cast<int>(lhs) == static_cast<int>(rhs);
}

template <int V>
bool operator==(typename TemplatedEnumerator<V>::Values rhs, Enumerator::Values lhs)
{
    return static_cast<int>(lhs) == static_cast<int>(rhs);
}

有趣的是,Visual Studio 实际上并没有警告比较两种枚举类型,而是警告if 语句中的常量值 - 就像你这样做一样:

if (true) {...}

【讨论】:

  • 我会非常犹豫是否要这样做。比较不同种类的枚举不应该是“正常工作”的事情。虽然偶尔需要它,但我相信在代码中明确表示它是可取的。您仍然可以将其包装在辅助函数中,但重载运算符似乎是错误的。
  • 如果这些枚举的存在只是为了比较它们(在模板元编程中很常见),那么允许它们进行比较似乎是一件合理的事情。请注意,这些运算符不会影响任何其他枚举的行为。
  • 感谢您的帮助 Josh,但 Konrad Rudolph 的解决方案似乎更新了,没有意识到这实际上可行,但您的假设是正确的。
【解决方案2】:

如果有 N 个枚举,是否不需要 N * (N - 1) 个比较运算符?这最终可能会很多。

难道你不能只使用枚举到整数的隐式转换并这样做:

bool equals(int lhs, int rhs)
{
  return lhs == rhs;
}

然后你可以在你的代码中这样做:

if(equals(Enumerator::VALUE, TemplatedEnumerator<5>::VALUE))
{
  ...
}

另外,您可以查看enum-int casting: operator or function。公认的答案是你不应该使用隐式转换,但是像 equals 这样正确命名的函数应该使代码非常可读和可维护。

【讨论】:

  • 您对代码量的看法是正确的,但经过全面优化,它们都会消失,因此不会有太多开销
  • "如果有 N 个枚举" - 那么我会认为这是代码异味。即使当 N==1 我会先检查设计 - 但这些事情有时会变得必要。您的解决方案的其余部分没问题 - 但“等于”可能这个名称太笼统了。那么“CompareDifferentEnums”呢?
  • 我同意必要性问题。但是,我认为在提出问题时已经考虑过这一点,并希望提供最简单的解决方案。不过我不确定这个名字,这个函数可以将任何整数与整数进行比较,而不仅仅是枚举。
【解决方案3】:

别这样。

警告是因为你不应该首先混淆不同的枚举。

对于常量,您可以使用 const 声明。

【讨论】:

  • 这是用于元编程的,我需要 enums ,可能对您的级别有所提高,但在 C++ 中生成模板代码是一种非常常见的模式。
  • 不,这个建议是有道理的,这里不需要枚举。
【解决方案4】:

在您的情况下简单回答:不要使用enum,使用内联定义的static const int

struct Enumerator
{
    static int const VALUE = 5;
};

template<int V>
struct TemplatedEnumerator
{
    static int const VALUE = V;
};

在这种特殊情况下,这是等效的,过去几年的所有编译器都应该这样处理(我知道所有主要的编译器都这样做)。

另请参阅:static const Member Value vs. Member enum : Which Method is Better & Why?

【讨论】:

  • 需要检查一下,也许这会起作用,但是这些枚举器正在做一些非常严肃的工作,所以我还不能说
  • 试了替换,成功了,谢谢!从大多数编译器没有正确处理静态 const 的那一天起,我就一直在我的技巧包中携带 enum hack!
【解决方案5】:
#include <iostream>
using namespace std;

struct Enumerator 
{
  enum {value = 5 };
};


template<int v>
struct TemplatedEnumerator
{ 
  enum {value = v};
};



int main(void)
{
  if (static_cast<int>(Enumerator::value) ==
    static_cast<int>(TemplatedEnumerator<5>::value))
    cout << "Yoh\n";
}

【讨论】:

    【解决方案6】:

    你错过了明显的答案。不,不要使用 c 风格的演员表。使用 C++ 风格的强制转换:

    if(static_cast<int>(Enumerator::VALUE) == static_cast<int>(TemplatedEnumerator<5>::VALUE))
    {
    
    }
    

    完全安全,完全可以接受。两个枚举不是相同的类型,因此如果您的代码中有任何可疑之处,则不是强制转换,而是尝试比较两种不同的类型。但只要你这样做,演员表将是我首选的方式。是的,您可以定义一个比较运算符,但是强制转换清楚地表明您正在比较两种技术上不相关的类型。

    【讨论】:

      猜你喜欢
      • 2014-03-10
      • 1970-01-01
      • 1970-01-01
      • 2011-03-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多