Прежде всего я хочу нормальное перечисление вместо основанного на битах перечисления, потому что количество различных перечислений будет вне любого целочисленного типа. Я также хочу воспользоваться преимуществами безопасности типов в C ++ 11 enum class
, Для этого естественным выбором будет std::bitset
Однако я понятия не имею, как связать эти два вместе.
Обычай bitset
понадобится? Как обойти реализацию такого класса?
поскольку enum class
Это обертки для перечислений, вы можете привести их к базовому типу. А используя частное наследование, вы можете выборочно импортировать некоторые функции из классов C ++ stdlib, не беспокоясь о принципе Лискова. Композиция привела к более четкому коду. Используя эти функции, мы можем обернуть std::bitset
, Следующий код содержит только подмножество функционалов, но он может быть расширен в дальнейшем.
Существует проблема с максимальным значением — вы не можете получить максимальное значение enum class
(или я не прав?). Итак, я добавил EnumTraits
, Теперь пользователи обязаны специализироваться EnumTraits
с постоянным значением max
равный максимальному значению enum перед использованием класса.
#include <bitset>
#include <type_traits>
template<typename T>
struct EnumTraits;
template<typename T>
class EnumClassBitset
{
private:
std::bitset<static_cast<typename std::underlying_type<T>::type>(EnumTraits<T>::max)> c;
typename std::underlying_type<T>::type get_value(T v) const
{
return static_cast<typename std::underlying_type<T>::type>(v);
}
public:
EnumClassBitset() : c()
{
}
bool test(T pos) const
{
return c.test(get_value(pos));
}
EnumClassBitset& reset(T pos)
{
c.reset(get_value(pos));
return *this;
}
EnumClassBitset& flip(T pos)
{
c.flip(get_value(pos));
return *this;
}
};
enum class BitFlags
{
False,
True,
FileNotFound,
Write,
Read,
MaxVal
};
template<>
struct EnumTraits<BitFlags>
{
static const BitFlags max = BitFlags::MaxVal;
};
#include <iostream>
int main()
{
EnumClassBitset<BitFlags> f;
f.flip(BitFlags::True);
f.flip(BitFlags::FileNotFound);
//f.flip(2); //fails to compile
std::cout << "Is False? " << f.test(BitFlags::False) << "\n";
std::cout << "Is True? " << f.test(BitFlags::True) << "\n";
std::cout << "Is FileNotFound? " << f.test(BitFlags::FileNotFound) << "\n";
std::cout << "Is Write? " << f.test(BitFlags::Write) << "\n";
std::cout << "Is Read? " << f.test(BitFlags::Read) << "\n";
}
поскольку enum
S, к сожалению, не так много функциональности, и, кроме того, C ++ 11 с enum class
не улучшай ситуацию, некоторые программисты используют статическую карту, заключенную в класс. Определенно хорошее чтение.
Других решений пока нет …