问题描述
我的位流类中有以下方法(广义上来说):
class BitStream
{
void StoreBits( unsigned int data,unsigned int numBits );
public:
template<typename T>
void WriteType( T value ) { StoreBits( value,sizeof(T) * 8 ) );
template<>
void WriteType( float value ) { StoreBits( *(unsigned int*)&value,sizeof(float) * 8 ) );
};
有人在WriteType上抛出了一个强类型的枚举类,显然该枚举不会自动转换为无符号整数。
我该怎么写才能使用相同的函数命名来处理所有枚举用例?
这是问题的琐事-我将枚举类实例抛出到我必须处理的许多其他BitStream成员方法上,例如ReadType,StreamType(读或写),SmallestRangeWrite
我有C ++ 17支持。我知道这里有std :: is_enum,但是我如何在这里专门研究它,尤其是在编译时?
我能以某种方式写:
template<typename T>inline void BitStream::WriteType( T value )
{
if (type_is_enum())
StoreEnum<T>(value)
else
StoreBits( value,sizeof(T) * 8 ) );
}
我需要确保在T为枚举时,不会编译StoreBits方法。仅仅在运行时避免使用分支是不够的。
解决方法
C ++ 17的最佳功能(这是我个人的看法)是 constexpr if 。这意味着您不需要定义显式的专业化。那会起作用:
template<typename T>inline void BitStream::WriteType(T value)
{
if constexpr (std::is_enum_v<T>)
StoreEnum<T>(value);
else
StoreBits(value,sizeof(T) * 8);
}
如果constexpr很重要,因为如果StoreEnum
类型的StoreBits
或T
未定义,则有编译失败的风险。
测试一下该类型是否为枚举,以及是否不能转换为u32
。这使您可以区分普通enum
和enum class
。如果它是一个枚举但不能转换为u32
,则它是enum class
:
template<typename T>
inline void BitStream::WriteType(T value)
{
if constexpr (std::is_enum_v<T> && !std::is_convertible_v<T,u32>)
// enum class
StoreEnum<T>(value)
else
// normal enum or other type that is convertible to u32
StoreBits(value,sizeof(T) * 8 ));
}
由于StoreEnum
和StoreBits
函数模板不能同时使用两者,因此您需要在此处使用if constexpr
以避免编译时进行类型检查。