#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;
}
The a::LOCAL_A
is what the strongly typed enum is trying to achieve, but there is a small difference : normal enums can be converted into integer type, while strongly typed enums can not do it without a cast.
So, is there a way to convert a strongly typed enum value into an integer type without a cast? If yes, how?
Strongly typed enums aiming to solve multiple problems and not only scoping problem as you mentioned in your question:
- Provide type safety, thus eliminating implicit conversion to integer by integral promotion.
- Specify underlying types.
- Provide strong scoping.
Thus, it is impossible to implicitly convert a strongly typed enum to integers, or even its underlying type - that's the idea. So you have to use static_cast
to make conversion explicit.
If your only problem is scoping and you really want to have implicit promotion to integers, then you better off using not strongly typed enum with the scope of the structure it is declared in.
As others have said, you can't have an implicit conversion, and that's by-design.
If you want you can avoid the need to specify the underlying type in the cast.
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;
A C++14 version of the answer provided by R. Martinho Fernandes would be:
#include <type_traits>
template <typename E>
constexpr auto to_underlying(E e) noexcept
{
return static_cast<std::underlying_type_t<E>>(e);
}
As with the previous answer, this will work with any kind of enum and underlying type. I have added the noexcept
keyword as it will never throw an exception.
Update
This also appears in Effective Modern C++ by Scott Meyers. See item 10 (it is detailed in the final pages of the item within my copy of the book).
#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;
}
No. There is no natural way.
In fact, one of the motivations behind having strongly typed enum class
in C++11 is to prevent their silent conversion to int
.
Hope this helps you or someone else
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;
}
The reason for the absence of implicit conversion (by design) was given in other answers.
I personally use unary operator+
for the conversion from enum classes to their underlying type:
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);
}
Which gives quite little "typing overhead":
std::cout << foo(+b::B2) << std::endl;
Where I actually use a macro to create enums and the operator functions in one shot.
#define UNSIGNED_ENUM_CLASS(name, ...) enum class name : unsigned { __VA_ARGS__ };\
inline constexpr unsigned operator+ (name const val) { return static_cast<unsigned>(val); }
Short answer is you can't as above posts point out. But for my case, I simply didn't want to clutter the namespace but still have implicit conversions, so I just did:
#include <iostream>
using namespace std;
namespace Foo {
enum { bar, baz };
}
int main() {
cout << Foo::bar << endl; // 0
cout << Foo::baz << endl; // 1
return 0;
}
The namespacing sort of adds a layer of type-safety while I don't have to static cast any enum values to the underlying type.
This seems impossible with the native enum class
, but probably you can mock a enum class
with a class
:
In this case,
enum class b
{
B1,
B2
};
would be equivalent to:
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;
}
};
This is mostly equivalent to the original enum class
. You can directly return b::B1
for in a function with return type b
. You can do switch case
with it, etc.
And in the spirit of this example you can use templates (possibly together with other things) to generalize and mock any possible object defined by the enum class
syntax.
As many said, there is no way to automatically convert without adding overheads and too much complexity, but you can reduce your typing a bit and make it look better by using lambdas if some cast will be used a bit much in a scenario. That would add a bit of function overhead call, but will make code more readable compared to long static_cast strings as can be seen below. This may not be useful project wide, but only class wide.
#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;
}
}
来源:https://stackoverflow.com/questions/8357240/how-to-automatically-convert-strongly-typed-enum-into-int