【问题标题】:Enumerator value made by or-ing other enumerators由或-ing其他枚举器产生的枚举器值
【发布时间】:2015-09-14 07:42:14
【问题描述】:

我在一个代表位标志的类中有一个枚举。

class Foo
{
    enum Bar
    {    
        BAR0 = 0x1,
        BAR1 = 0x2,
        BAR2 = 0x4,    
    };
}

我还为类 Foo 之外的枚举 Bar 定义了一个 operator|

constexpr Foo::Bar operator| (Foo::Bar lhs, Foo::Bar rhs) 
{ 
    return static_cast<Foo::Bar>(static_cast<int>(lhs) | static_cast<int>(rhs)); 
} 

我还希望有一个constexpr 变量BAR_ALL,它是Foo 类中Bar 的所有现有标志的组合。我尝试了以下但它没有编译错误error: #28: expression must have a constant value

完整代码:

class Foo
{
    enum Bar
    {    
        BAR0 = 0x1,
        BAR1 = 0x2,
        BAR2 = 0x4,    
    };
    friend constexpr Bar operator| (Bar lhs, Bar rhs); 
    static constexpr Bar BAR_ALL = BAR0 | BAR1 | BAR2;
};

constexpr Foo::Bar operator| (Foo::Bar lhs, Foo::Bar rhs) 
{ 
    return static_cast<Foo::Bar>(static_cast<int>(lhs) | static_cast<int>(rhs)); 
} 

我想编译器不知道BAR0 | BAR1 | BAR2constexpr 是有道理的,因为该运算符是在代码后面定义的。我的问题是如何获得变量Foo::BAR_ALLconstexpr 的预期效果。

提前感谢您的建议/帮助!

【问题讨论】:

  • 你可能打算写BAR1而不是BAR 1
  • 您是否尝试过使用 static constexpr int BAR0 = 0x1;等等?
  • @BoPersson 是的,谢谢。
  • @choosyg 我希望变量是枚举,所以它们有自己的类型。将来我可能会把它变成一个枚举类。我正在将我的项目从 C++03 移植到 C++11。
  • 我不认为问题在于编译器不知道operator| 不是const_expr,你声明它是......我看到的更大问题是你投了@ 987654340@ 到 Foo::Bar 当您可以退出声明的值时。例如。你可以有3,但没有对应的Bar。这甚至允许吗?

标签: c++ c++11


【解决方案1】:

这是一个具有您想要的功能的工作版本。

class Foo
{
    enum Bar
    {
        BAR0 = 0x1,
        BAR1 = 0x2,
        BAR2 = 0x4,
        BAR_ALL_ = BAR0 | BAR1 | BAR2
    };
    friend constexpr Bar operator| (Bar lhs, Bar rhs);

public:
    static Bar constexpr BAR_ALL = Bar::BAR_ALL_;
};

constexpr Foo::Bar operator| (Foo::Bar lhs, Foo::Bar rhs)
{
    return static_cast<Foo::Bar>(static_cast<int>(lhs) | static_cast<int>(rhs));
}

template <int I>
struct test_constexpr_bar_all {};

int main()
{
    int x{ 5 };
    // test_constexpr_bar_all<x> t1; // fails to compile because x is not a constexpr
    test_constexpr_bar_all<Foo::BAR_ALL> t1; // compiles properly
}

如果你想公开你的枚举,那么你可以去掉static Bar constexpr BAR_ALL = Bar::BAR_ALL_;,直接通过Foo::Bar::BAR_ALL_访问它。

我会这样做:

class Foo
{
public:
    enum Bar
    {
        BAR0 = 0x1,
        BAR1 = 0x2,
        BAR2 = 0x4,
        BAR_ALL = BAR0 | BAR1 | BAR2
    };
private:
    friend constexpr Bar operator| (Bar lhs, Bar rhs);
};

constexpr Foo::Bar operator| (Foo::Bar lhs, Foo::Bar rhs)
{
    return static_cast<Foo::Bar>(static_cast<int>(lhs) | static_cast<int>(rhs));
}

template <Foo::Bar I>
struct test_constexpr_bar_all {};

int main()
{
    test_constexpr_bar_all<Foo::Bar::BAR_ALL> t1;
}

【讨论】:

  • 谢谢。是的,在我的原始代码中,枚举是公开的。您的代码确实可以编译,这就是我用 C++03 编写的方式。但它不能用我的嵌入式编译器编译,但编译器错误相同。我想我将无法将 BAR_ALL 保留为 constexpr。感谢您的帮助:)
【解决方案2】:

您被编译器错误误导了。实际上,您的代码有几个错误(评论者似乎错过了,因为他们没有费心尝试编译它。)

  1. BAR 1BAR 2

  2. BAR_ALL 没有类型

  3. 您尝试在定义之前使用operator|

修复所有这些错误会生成以下代码:

class Foo
{
    enum Bar
    {    
        BAR0 = 0x1,
        BAR1 = 0x2,
        BAR2 = 0x4,    
    };

    static constexpr int BAR_ALL = BAR0 | BAR1 | BAR2;
};

从评论看来,您正在尝试将 C++03 移植到 C++11 代码。问问自己:enum class 真的 适合吗?如果您不完全了解其中的含义,或者如果由此产生的维护成本超过收益,请不要强加功能。

【讨论】:

  • @user5332965 你应该进一步解释。如果不是枚举类比什么?不要给 rozina 留下谜题!
  • 感谢您发现编译器错误。我没有尝试编译示例代码,我的错 :) 您的解决方案更改了不需要的 BAR_ALL 类型。而且我认为我了解枚举的使用,并且在 C++11 之前它们对位标志很有用。在 c++11 中,我希望它们作为枚举类更加有用,因为它们将是强类型的。
  • @bku_drytt 关心提供编译器版本吗? Here's a live example 用于 Clang。它也适用于 GCC。
  • @kleszcz 枚举类并不是要替换枚举,就像基于范围的 for 循环不是要替换 for 循环一样。它们是不同的功能,请使用最适合应用需求的功能。
  • @user5332965 我一定是在复制您的代码时出错了。它工作正常。对不起。
猜你喜欢
  • 2020-05-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-09-23
  • 1970-01-01
  • 2013-04-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多