2012-07-10 49 views
56

如何在C++ 11中输出enum class的值?在C++ 03是这样的:如何在C++ 11中输出枚举类的值11

#include <iostream> 

using namespace std; 

enum A { 
    a = 1, 
    b = 69, 
    c= 666 
}; 

int main() { 
    A a = A::c; 
    cout << a << endl; 
} 

中的C++ 0x这段代码不能编译

#include <iostream> 

using namespace std; 

enum class A { 
    a = 1, 
    b = 69, 
    c= 666 
}; 

int main() { 
    A a = A::c; 
    cout << a << endl; 
} 


prog.cpp:13:11: error: cannot bind 'std::ostream' lvalue to 'std::basic_ostream<char>&&' 
/usr/lib/gcc/i686-pc-linux-gnu/4.5.1/../../../../include/c++/4.5.1/ostream:579:5: error: initializing argument 1 of 'std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&&, const _Tp&) [with _CharT = char, _Traits = std::char_traits<char>, _Tp = A]' 

Ideone.com

+1

为什么你要输出枚举?枚举类用于不混淆枚举值与int表示 – RiaD 2012-07-10 20:31:37

回答

75

编译不像无范围枚举,一个作用域枚举不是含蓄可转换为其整数值。您需要明确使用强制将其转换为整数:

std::cout << static_cast<std::underlying_type<A>::type>(a) << std::endl; 

您可能需要逻辑封装成函数模板:

template <typename Enumeration> 
auto as_integer(Enumeration const value) 
    -> typename std::underlying_type<Enumeration>::type 
{ 
    return static_cast<typename std::underlying_type<Enumeration>::type>(value); 
} 

用作:

std::cout << as_integer(a) << std::endl; 
+1

是否有一个原因使用尾随返回类型语法? – 2012-07-10 20:41:13

+0

@NicolBolas:我从我的一个开源库CxxReflect中复制了'as_integer'(参见[enumeration.hpp](http://cxxreflect.codeplex.com/SourceControl/changeset/view/8ffbb562ad38#cxxreflect%2fcore%2fenumeration) .HPP))。该库一直使用尾随返回类型,无处不在。为了一致。 – 2012-07-10 20:42:17

+6

虽然这是迟了2年,万一有人看到这个问题,你可以使用上面的演员技巧方法,只需调用“static_cast (value)”来获得整数或“static_cast (intValue)”以获得枚举值。请记住,从int到枚举或枚举到枚举可能会导致问题,并且通常通常是设计错误的标志。 – 2014-04-16 21:23:51

26
#include <iostream> 
#include <type_traits> 

using namespace std; 

enum class A { 
    a = 1, 
    b = 69, 
    c= 666 
}; 

std::ostream& operator << (std::ostream& os, const A& obj) 
{ 
    os << static_cast<std::underlying_type<A>::type>(obj); 
    return os; 
} 

int main() { 
    A a = A::c; 
    cout << a << endl; 
} 
+0

我逐字拷贝了这个例子,并将其编译为'g ++ -std = C++ 0x enum.cpp',但是我收到了一堆编译器错误 - > http://pastebin.com/JAtLXan9。我也无法从@ james-mcnellis得到编译的例子。 – Dennis 2013-05-17 23:18:43

+3

@Dennis [underlying_type](http://www.cplusplus.com/reference/type_traits/underlying_type/)仅适用于C++ 11 – Deqing 2013-08-08 02:03:42

9

(我不允许评论。)我会建议以下改进詹姆斯McNellis的已经很大答案:

template <typename Enumeration> 
constexpr auto as_integer(Enumeration const value) 
    -> typename std::underlying_type<Enumeration>::type 
{ 
    static_assert(std::is_enum<Enumeration>::value, "parameter is not of type enum or enum class"); 
    return static_cast<typename std::underlying_type<Enumeration>::type>(value); 
} 

  • constexpr:让我用枚举成员的值作为编译时数组大小
  • static_assert + is_enum:以“确保”编译当这个函数做某事的时候。与建议

顺便说一句我问自己:为什么我应该使用enum class当我想为我的枚举成员分配数值?!考虑到转换工作。

也许我会再回到普通enum我这里建议:How to use enums as flags in C++?


然而,它的另一个(更好)风味,而没有static_assert,基于@TobySpeight的建议:

template <typename Enumeration> 
constexpr std::enable_if_t<std::is_enum<Enumeration>::value, 
std::underlying_type_t<Enumeration>> as_number(const Enumeration value) 
{ 
    return static_cast<std::underlying_type_t<Enumeration>>(value); 
} 
+0

是否存在类型为“T”的std :: underlying_type为 :: type '存在,但'std :: is_enum :: value'是错误的?如果不是,那么'static_assert'不会添加任何值。 – 2017-02-08 08:40:31

+0

我没有在所有的编译器上测试。但是,@ TobySpeight你可能是正确的,msvc2013似乎吐出易于理解的错误信息,暗示了underlying_type_t存在与类型本身之间是1:1对应的枚举。而static_assert甚至没有被解雇。但是:参考文献指出,如果未提供完整的枚举类型,那么underlying_type的行为是未定义的。所以static_assert只是希望得到最大可理解的消息。也许有可能迫使它得到更早/最早的处理? – yau 2017-02-08 10:15:49

+0

啊,是的,如果'Enumeration'不是一个完整的枚举类型,那么它是未定义的。在这种情况下,它可能已经太晚了,因为它用于返回类型。也许我们可以指定'std :: enable_if :: value,std :: underlying_type :: type>'作为返回类型?当然,如果你有一个支持Concepts的编译器,那么它更容易(和错误消息更清晰)... – 2017-02-08 10:22:29

14

可以使用与无范围枚举相同的语法来获得第二个示例(即使用范围枚举的示例)。此外,解决方案是通用的,并且适用于所有范围枚举,而不是为每个范围枚举编写代码(如@ForEveR提供的answer所示)。

解决方法是编写一个通用的operator<<函数,该函数将适用于任何范围枚举。该解决方案通过std::enable_if采用SFINAE,如下所示。

#include <iostream> 
#include <type_traits> 

// Scoped enum 
enum class Color 
{ 
    Red, 
    Green, 
    Blue 
}; 

// Unscoped enum 
enum Orientation 
{ 
    Horizontal, 
    Vertical 
}; 

// Another scoped enum 
enum class ExecStatus 
{ 
    Idle, 
    Started, 
    Running 
}; 

template<typename T> 
std::ostream& operator<<(typename std::enable_if<std::is_enum<T>::value, std::ostream>::type& stream, const T& e) 
{ 
    return stream << static_cast<typename std::underlying_type<T>::type>(e); 
} 

int main() 
{ 
    std::cout << Color::Blue << "\n"; 
    std::cout << Vertical << "\n"; 
    std::cout << ExecStatus::Running << "\n"; 
    return 0; 
} 
+0

你需要'std :: underlying_type :: type'之前的'typename'。 – uckelman 2015-02-21 14:39:34

+0

@uckelman你绝对正确。感谢您更新我的答案。 – 2015-02-21 14:44:23

+0

这对clang工作适用于我,但在gcc 4.9.2下,这个解决方案失败时,链接<<一起,与错误 错误:不能绑定'std :: basic_ostream '左值为'std :: basic_ostream &&' '。这似乎是因为当流是暂时的,ADL失败,并且上述模板不可能。有小费吗? – ofloveandhate 2015-09-14 21:15:13