BЈо*_*вић 144 c++ c++11 strongly-typed-enum
#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;
}
Run Code Online (Sandbox Code Playgroud)
这a::LOCAL_A
是强类型枚举试图实现的,但有一个小的区别:普通枚举可以转换为整数类型,而强类型枚举不能没有强制转换.
那么,有没有办法将强类型的枚举值转换为没有强制转换的整数类型?如果有,怎么样?
R. *_*des 141
正如其他人所说的那样,你不能进行隐式转换,这是设计的.
如果需要,可以避免在强制转换中指定基础类型.
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;
Run Code Online (Sandbox Code Playgroud)
小智 120
强类型枚举旨在解决多个问题,而不仅仅是您在问题中提到的范围问题:
因此,不可能将强类型枚举隐式转换为整数,甚至是它的基础类型 - 这就是想法.所以你必须使用static_cast
显式转换.
如果您唯一的问题是作用域并且您确实希望对整数进行隐式提升,那么最好使用非强类型枚举,并将其声明为结构的范围.
希望能帮助到你!
Cla*_*ton 67
R. Martinho Fernandes提供的答案的C++ 14版本将是:
#include <type_traits>
template <typename E>
constexpr auto to_underlying(E e) noexcept
{
return static_cast<std::underlying_type_t<E>>(e);
}
Run Code Online (Sandbox Code Playgroud)
与前面的答案一样,这适用于任何类型的枚举和底层类型.我添加了noexcept
关键字,因为它永远不会抛出异常.
更新
这也出现在Scott Meyers的Effective Modern C++中.见第10项(在我的书副本中的项目的最后几页详细说明).
Khu*_*dov 18
#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;
}
Run Code Online (Sandbox Code Playgroud)
vis*_*.15 13
希望这可以帮助你或其他人
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;
}
Run Code Online (Sandbox Code Playgroud)
Pix*_*ist 13
在其他答案中给出了缺乏隐式转换(设计)的原因.
我个人使用一元operator+
进行从枚举类到其基础类型的转换:
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);
}
Run Code Online (Sandbox Code Playgroud)
这给了很少的"打字开销":
std::cout << foo(+b::B2) << std::endl;
Run Code Online (Sandbox Code Playgroud)
我实际上使用宏来创建枚举和操作符一次性运行.
#define UNSIGNED_ENUM_CLASS(name, ...) enum class name : unsigned { __VA_ARGS__ };\
inline constexpr unsigned operator+ (name const val) { return static_cast<unsigned>(val); }
Run Code Online (Sandbox Code Playgroud)
sol*_*333 11
简短的回答是你不能像上面的帖子所指出的那样.但对于我的情况,我只是不想混淆命名空间但仍然有隐式转换,所以我只是做了:
#include <iostream>
using namespace std;
namespace Foo {
enum Foo { bar, baz };
}
int main() {
cout << Foo::bar << endl; // 0
cout << Foo::baz << endl; // 1
return 0;
}
Run Code Online (Sandbox Code Playgroud)
命名空间类型添加了一个类型安全层,而我不必将任何枚举值静态转换为基础类型.
C++ 委员会向前迈了一步(将枚举范围排除在全局命名空间之外),又后退了 50 步(没有枚举类型衰减为整数)。遗憾的是,enum class
如果您需要以任何非符号方式获取枚举的值,则根本无法使用。
最好的解决方案是根本不使用它,而是使用命名空间或结构自行确定枚举的范围。为此,它们是可以互换的。当引用枚举类型本身时,您需要额外输入一些内容,但这可能不会经常发生。
struct TextureUploadFormat {
enum Type : uint32 {
r,
rg,
rgb,
rgba,
__count
};
};
// must use ::Type, which is the extra typing with this method; beats all the static_cast<>()
uint32 getFormatStride(TextureUploadFormat::Type format){
const uint32 formatStride[TextureUploadFormat::__count] = {
1,
2,
3,
4
};
return formatStride[format]; // decays without complaint
}
Run Code Online (Sandbox Code Playgroud)
对于本机来说这似乎是不可能的enum class
,但可能你可以用以下方法模拟enum class
a class
:
在这种情况下,
enum class b
{
B1,
B2
};
Run Code Online (Sandbox Code Playgroud)
相当于:
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;
}
};
Run Code Online (Sandbox Code Playgroud)
这大致相当于原版enum class
.您可以b::B1
在具有返回类型的函数中直接返回b
.你可以switch case
用它等
在本示例的精神中,您可以使用模板(可能与其他东西一起)来概括和模拟enum class
语法定义的任何可能的对象.
正如许多人所说,没有办法在不增加开销和太多复杂性的情况下自动转换,但是如果在某个场景中使用了一些强制转换,您可以通过使用 lambda 来减少输入并使其看起来更好。这会增加一些函数开销调用,但与长的 static_cast 字符串相比,会使代码更具可读性,如下所示。这可能在项目范围内没有用,而只是在类范围内有用。
#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;
}
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
188011 次 |
最近记录: |