Обычно вы можете определить бросок для класса, используя следующий синтаксис:
class Test {
public:
explicit operator bool() { return false; }
};
Есть ли способ сделать это или что-то подобное для enum class
?
Обычно вы можете определить бросок для класса, используя следующий синтаксис:
class Test {
public:
explicit operator bool() { return false; }
};
Есть ли способ сделать это или что-то подобное для enum class
?
Нет, это не так.
Собственно, enum class
не является классом вообще. Ключевое слово class
используется только потому, что внезапное изменение незанятого enum
на область enum
означало бы переработку всех кодов перечислений. Таким образом, комитет решил, что для различения записей нового стиля и старого стиля новые будут помечены class
, потому что это ключевое слово уже, поэтому no enum
можно было бы назвать class
в С++. Они могли бы выбрать другую, это не имело бы никакого смысла.
Однако, несмотря на ключевое слово class
, они все еще являются регулярными перечислениями, поскольку в скобках допускаются только перечисляющие (и потенциально назначенные им значения).
Нет, но вы можете заставить нормальный тип класса действовать как класс enum, используя члены и конструкторы constexpr
. И тогда вы можете добавить все дополнительные функции-члены, которые вы хотите.
Доказательство того, что он может работать даже с switch
:
#include <iostream>
struct FakeEnum
{
int x;
constexpr FakeEnum(int y = 0) : x(y) {}
constexpr operator int() const { return x; }
static const FakeEnum A, B, Z;
};
constexpr const FakeEnum FakeEnum::A{1}, FakeEnum::B{2}, FakeEnum::Z{26};
std::istream& operator>>(std::istream& st, FakeEnum& fe)
{
int val;
st >> val;
fe = FakeEnum{val};
return st;
}
int main()
{
std::cout << "Hello, world!\n";
FakeEnum fe;
std::cin >> fe;
switch (fe)
{
case FakeEnum::A:
std::cout << "A\n";
break;
case FakeEnum::B:
std::cout << "B\n";
break;
case FakeEnum::Z:
std::cout << "Z\n";
break;
}
}
Доказательство того, что работа с switch
не требует неявного взаимопревращения с int
:
#include <iostream>
/* pseudo-enum compatible with switch and not implicitly convertible to integral type */
struct FakeEnum
{
enum class Values { A = 1, B = 2, Z = 26 };
Values x;
explicit constexpr FakeEnum(int y = 0) : FakeEnum{static_cast<Values>(y)} {}
constexpr FakeEnum(Values y) : x(y) {}
constexpr operator Values() const { return x; }
explicit constexpr operator bool() const { return x == Values::Z; }
static const FakeEnum A, B, Z;
};
constexpr const FakeEnum FakeEnum::A{Values::A}, FakeEnum::B{Values::B}, FakeEnum::Z{Values::Z};
std::istream& operator>>(std::istream& st, FakeEnum& fe)
{
int val;
st >> val;
fe = FakeEnum(val);
return st;
}
int main()
{
std::cout << "Hello, world!\n";
FakeEnum fe;
std::cin >> fe;
switch (fe)
{
case FakeEnum::A:
std::cout << "A\n";
break;
case FakeEnum::B:
std::cout << "B\n";
break;
case FakeEnum::Z:
std::cout << "Z\n";
break;
}
// THIS ERRORS: int z = fe;
}
Вы не можете определить операторы-литеры, не являющиеся членами, в С++. И вы, конечно, не можете определить функции-члены для перечислений. Поэтому я предлагаю вам делать бесплатные функции для преобразования вашего перечисления в другие типы, так же, как и для операторов трансляции.
например.
bool TestToBool(enum_e val)
{
return false;
}
const char *TestToString(enum_e val)
{
return "false";
}
Есть хороший способ связать эти перечисления с bools, вам нужно разбить его на два файла .h и .cpp. Вот оно, если это помогает:
enum.h
///////////////////////////////
// enum.h
#ifdef CPP_FILE
#define ENUMBOOL_ENTRY(A, B) { (enum_e) A, (bool) B },
struct EnumBool
{
enum_e enumVal;
bool boolVal;
};
#else
#define ENUMBOOL_ENTRY(A, B) A,
#endif
#ifdef CPP_FILE
static EnumBool enumBoolTable[] = {
#else
enum enum_e
{
#endif
ENUMBOOL_ENTRY(ItemA, true),
ENUMBOOL_ENTRY(ItemB, false),
...
};
bool EnumToBool(enum_e val);
enum.cpp
///////////////////////////////
// enum.cpp
#define CPP_FILE
#include "enum.h"
bool EnumToBool(enum_e val)
//implement
Я не скомпилировал его, так что не стесняйтесь, если у него есть какие-либо ошибки:).