有没有一种方法可以使枚举类型成为无符号类型?

11
有没有一种方法可以使枚举类型成为无符号的?以下代码给我一个关于有符号/无符号比较的警告。
enum EEE {
    X1 = 1
};

int main()
{
    size_t x = 2;
    EEE t = X1;
    if ( t < x ) std::cout << "ok" << std::endl;

    return 0;
}

我尝试使用以下代码强制编译器使用无符号的枚举基础类型:

enum EEE {
    X1 = 1,
    XN = 18446744073709551615LL
    // I've tried XN = UINT_MAX (in Visual Studio). Same warning.
};

但是仍然会出现警告。


将常量更改为UINT_MAX,使其在GNU C++中按照标准应该工作。在VS中似乎存在一个错误。感谢James的提示。


相关但不重复:https://dev59.com/dnE85IYBdhLWcg3w2Hbs - James McNellis
https://dev59.com/qXVC5IYBdhLWcg3w21Mq - sbi
2
@sbi,这不是重复的问题,因为C++标准提供了如何将底层类型更改为unsigned int的提示。我正在尝试使用它。 - Kirill V. Lyadvinsky
1
@Sbi,下次请复制并粘贴完整的URL。Stack Overflow会将其缩写为您发布的内容,但是当您包含整个URL时,我们可以获得工具提示显示问题标题(实际上是URL的剩余部分),而无需访问链接。将您的帖子与James的评论进行比较。 - Rob Kennedy
@Rob:你说得对,在这种情况下这样做会更好。我已经养成了剪掉冗余部分的习惯,因为评论的空间有限。 - sbi
6个回答

8
你可以尝试以下方法:
enum EEE {
    X1 = 1,
    XN = -1ULL
};

没有使用U时,整数字面量是带符号的。
(当然,这假设您的实现支持long long;我假设它支持,因为原始问题使用了LL;否则,您可以使用UL表示long)。

1
这在GNU C++中可以工作,但在Visual Studio中不行。看起来是VS的一个bug。这段代码也是正确的,但最好使用UINT_MAX - Kirill V. Lyadvinsky
@James,啊,确实。如果你使用“LLU”而不是像我一样只用“U”,它就不能再选择“long”了。这是一个避免“更大”含义不清的好方法!如果你使用限制宏或-1ULL(或在C++03或long long实现中使用-1UL),我会点赞的 :) - Johannes Schaub - litb
ULLONG_MAX 在 VC++ 中也无法工作。我认为编译器认为它可以生成 128 位的代码。 - Kirill V. Lyadvinsky
1
@Johannes:谢谢您提醒我-1的技巧,我已经忘记了。 - James McNellis
1
@Kirill:无论我给枚举器什么值,它在 VS2008 中始终具有四个字节的大小。 :-/ - James McNellis

2

如果您想进行比较,还可以重载运算符。

enum EEE {
    X1 = 1
};

bool operator<(EEE e, std::size_t u) {
  return (int)e < (int)u;
}

然而,对于右侧的任何整数类型,您都必须执行该操作。否则,如果您执行 e < 2,它将是模棱两可的:编译器可能使用您的 operator< 正好匹配左侧,但需要在右侧进行转换,或者使用其内置运算符,需要提升左侧并正好匹配右侧。

因此,最终,我会放置以下版本:

/* everything "shorter" than "int" uses either int or unsigned */
bool operator<(EEE e, int u) {
  return (int)e < (int)u;
}

bool operator<(EEE e, unsigned u) {
  return (unsigned int)e < (unsigned int)u;
}


bool operator<(EEE e, long u) {
  return (long)e < (long)u;
}

bool operator<(EEE e, unsigned long u) {
  return (unsigned long)e < (unsigned long)u;
}

/* long long if your compiler has it, too */

虽然不太好看,但至少您的枚举用户很容易理解。但是,如果您最终不想与普通的int进行比较,而是想与某些有意义的值进行比较,我建议您采纳某个人提出的建议,添加另一个枚举器,其值为2,并命名它。这样,警告也会消失。


-1U?你试图对无符号类型应用一元减运算符吗?这是否应该更改为有符号类型? - Kirill V. Lyadvinsky
@Kirill,它将保持为“unsigned”,但其值将更改为“UINT_MAX”。因此,您不需要limits头文件。 - Johannes Schaub - litb
我移除了使用 UINT_MAX 的“技巧”,因为我认为“larger”的意思实际上是“sizeof”值-即“类型大小”(在向 dgregor 提问后)。 "long" 可能与 "unsigned int" 相同,因此仍然可以选择 "long"。唯一安全的方法似乎是使用 @James 的解决方案,并在不使用强制转换和运算符重载等枚举的情况下使用 -1ULL - Johannes Schaub - litb
“-1ULL” 看起来很有前途,但在 Visual Studio 中也不起作用。我将尝试在 VS 错误跟踪器中发布错误。 - Kirill V. Lyadvinsky
@Matthieu 是的,我怀疑我们可以使用那样的模板。 - Johannes Schaub - litb
显示剩余2条评论

2

当前版本的C++不支持强类型枚举,但C++0x将提供这一功能。

暂时可以使用if ( static_cast<size_t>(t) < x )来消除警告。


2
我正在尝试避免额外的 static_cast - Kirill V. Lyadvinsky

1

1

@KirillV.Lyadvinsky:真的吗?应该可以。自MSVC2005以来,MSVC就说它可以编译这个。 - Mooing Duck
1
我在参考文献中搜索了"unsigned",但是并没有像你上面提供的那样出现。 "unsigned"仅在一个句子中使用。 你确定该参考文献是正确的吗? - jww
@jww 好的,那句话解释了它应该如何使用。对“type”的引用是对文章顶部的原理声明的引用:enum [tag] [: type] ...。因此,它表明那里的“type”可以是任何标量有符号或无符号整数类型。这应该肯定有效。它在我的VS 2010上编译,但会出现警告C4480(使用非标准扩展:为枚举指定底层类型)。 - Cody Gray

0

为什么不呢

enum EEE {
    X1 = 1,
    x = 2 // pick more descriptive name, a'course
};

或者

if ( size_t( t ) < x )

2
你怎么知道枚举EEE的枚举值是无符号的?它们看起来像整数。 - chollida
@chollida,最终目标是消除警告,而不是将其设为无符号。我猜他的方式确实实现了这一点。 - Johannes Schaub - litb
@cohollida:问题是如何使枚举类型无符号。这意味着他不会放入负值,或者如果他这样做了,他想要模算术。 - Potatoswatter

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接