如何自动将强types枚举转换为int?
#include <iostream> struct a { enum LOCAL_A { A1, A2 }; }; enum class b { B1, B2 }; int foo( int input ) { return input; } int main(void) { std::cout<<foo(a::A1)<<std::endl; std::cout<<foo(static_cast<int>(b::B2))<<std::endl; }
a::LOCAL_A
是强types枚举试图实现的内容,但是有一点区别:普通枚举可以转换为整数types,而强types枚举不能没有a::LOCAL_A
转换。
那么,有没有办法将一个强types的枚举值转换为一个整型没有转换? 如果是的话,怎么样?
强烈types的枚举旨在解决多个问题,而不仅仅是您在问题中提到的范围问题:
- 提供types安全性,从而通过整体提升消除隐式转换为整数。
- 指定基础types。
- 提供强有力的范围。
因此,不可能将一个强types的枚举隐式转换为整数,甚至是其基本types – 这就是想法。 所以你必须使用static_cast
来明确地进行转换。
如果你唯一的问题是范围确定,你真的想隐式地提升整数,那么你最好不要使用强types的枚举与它所声明的结构的范围。
希望能帮助到你!
正如其他人所说,你不能有一个隐式的转换,这是通过devise。
如果你想要的话,你可以避免需要在演员中指定基础types。
template <typename E> constexpr typename std::underlying_type<E>::type to_underlying(E e) noexcept { return static_cast<typename std::underlying_type<E>::type>(e); } std::cout << foo(to_underlying(b::B2)) << std::endl;
R. Martinho Fernandes提供的C ++ 14版本的答案是:
template <typename E> constexpr auto to_underlying(E e) noexcept { return static_cast<std::underlying_type_t<E>>(e); }
和前面的答案一样,这将适用于任何种类的枚举和底层types。 我添加了noexcept
关键字,因为它永远不会抛出exception。
更新
这也出现在Scott Meyers的Effective Modern C ++中 。 参见第10项(在本书副本的最后一页中有详细说明)。
#include <cstdlib> #include <cstdio> #include <cstdint> #include <type_traits> namespace utils { namespace details { template< typename E > using enable_enum_t = typename std::enable_if< std::is_enum<E>::value, typename std::underlying_type<E>::type >::type; } // namespace details template< typename E > constexpr inline details::enable_enum_t<E> underlying_value( E e )noexcept { return static_cast< typename std::underlying_type<E>::type >( e ); } template< typename E , typename T> constexpr inline typename std::enable_if< std::is_enum<E>::value && std::is_integral<T>::value, E >::type to_enum( T value ) noexcept { return static_cast<E>( value ); } } // namespace utils int main() { enum class E{ a = 1, b = 3, c = 5 }; constexpr auto a = utils::underlying_value(E::a); constexpr E b = utils::to_enum<E>(5); constexpr auto bv = utils::underlying_value(b); printf("a = %d, b = %d", a,bv); return 0; }
不,没有自然的方式 。
实际上,在C ++ 11中强types化enum class
的动机之一就是防止它们无声地转换为int
。
希望这可以帮助你或其他人
enum class EnumClass : int //set size for enum { Zero, One, Two, Three, Four }; union Union //This will allow us to convert { EnumClass ec; int i; }; int main() { using namespace std; //convert from strongly typed enum to int Union un2; un2.ec = EnumClass::Three; cout << "un2.i = " << un2.i << endl; //convert from int to strongly typed enum Union un; un.i = 0; if(un.ec == EnumClass::Zero) cout << "True" << endl; return 0; }
这对于本地enum class
似乎是不可能的,但是可能你可以用一个class
来模拟一个enum class
class
:
在这种情况下,
enum class b { B1, B2 };
将相当于:
class b { private: int underlying; public: static constexpr int B1 = 0; static constexpr int B2 = 1; b(int v) : underlying(v) {} operator int() { return underlying; } };
这大多相当于原来的enum class
。 你可以直接返回b::B1
在返回types为b
的函数中。 你可以用它来switch case
等
在这个例子的精神,你可以使用模板(可能与其他事情一起)概括和嘲笑由enum class
语法定义的任何可能的对象。
正如很多人所说,没有任何方法可以自动转换而不会增加开销和太复杂,但是如果在场景中使用一些演员,可以使用lambdaexpression式来减less打字次数并使其看起来更好。 这将增加一些函数开销调用,但是与长static_caststring相比,这会使代码更具可读性,如下所示。 这可能不是有用的项目范围,但只有类宽。
#include <bitset> #include <vector> enum class Flags { ......, Total }; std::bitset<static_cast<unsigned int>(Total)> MaskVar; std::vector<Flags> NewFlags; ----------- auto scui = [](Flags a){return static_cast<unsigned int>(a); }; for (auto const& it : NewFlags) { switch (it) { case Flags::Horizontal: MaskVar.set(scui(Flags::Horizontal)); MaskVar.reset(scui(Flags::Vertical)); break; case Flags::Vertical: MaskVar.set(scui(Flags::Vertical)); MaskVar.reset(scui(Flags::Horizontal)); break; case Flags::LongText: MaskVar.set(scui(Flags::LongText)); MaskVar.reset(scui(Flags::ShorTText)); break; case Flags::ShorTText: MaskVar.set(scui(Flags::ShorTText)); MaskVar.reset(scui(Flags::LongText)); break; case Flags::ShowHeading: MaskVar.set(scui(Flags::ShowHeading)); MaskVar.reset(scui(Flags::NoShowHeading)); break; case Flags::NoShowHeading: MaskVar.set(scui(Flags::NoShowHeading)); MaskVar.reset(scui(Flags::ShowHeading)); break; default: break; } }
其他答案给出了没有隐式转换(按devise)的原因。
我个人使用一元运算operator+
从enum类到其基础types的转换:
template <typename T> constexpr auto operator+(T e) noexcept -> std::enable_if_t<std::is_enum<T>::value, std::underlying_type_t<T>> { return static_cast<std::underlying_type_t<T>>(e); }
这几乎没有“打字开销”:
std::cout << foo(+b::B2) << std::endl;
在哪里我实际上使用macros创build枚举和操作员function在一个镜头。
#define UNSIGNED_ENUM_CLASS(name, ...) enum class name : unsigned { __VA_ARGS__ };\ inline constexpr unsigned operator+ (name const val) { return static_cast<unsigned>(val); }
简短的回答是你不能像上面的post所指出的那样。 但对于我的情况,我根本不想混乱命名空间,但仍然有隐含的转换,所以我只是:
#include <iostream> using namespace std; namespace Foo { enum { bar, baz }; } int main() { cout << Foo::bar << endl; // 0 cout << Foo::baz << endl; // 1 return 0; }
命名空间的种类增加了一个types安全的层,而我不必静态地将任何枚举值转换为基础types。