Пару лет назад я задал вопрос , используя пример для имитации богатого Java-подобного класса enum в C ++ 0x.Я прошу предложений о том, как улучшить дизайн с целью (1) обработки constexpr и (2) избегания ручных шагов, где я эффективно (а) объявляю вложенные значения перечисления, (б) объявляю и, надеюсь, скоро constexpr инициализируетстатические поля и (c) инициализируют множество строго слабых упорядоченных перечислений.Интересно, могут ли шаблоны помочь в этой области?
Код довольно прост и показан в следующей coliru live демонстрационной версии.
В частности, я хотел иметь возможность:
- включить значения.
В приведенном ниже фрагменте кода показано, как это работает, ограничение заключалось в том, что вместо включенияBetterEnum :: EnumValue1, мне пришлось вместо этого включить вложенное значение enum - это не очевидно, но в нем используется встроенный оператор приведения:
//! Integral cast operator for switch statements (cast to named enum).
constexpr operator const Value() const noexcept {
return mValue;
}
Я не уверен, как обойти это ограничение.
BetterEnum val = BetterEnum::EnumValue1;
switch (val) {
case BetterEnum::enumvalue1:
std::cout << BetterEnum::EnumValue1.getStringVal() << std::endl;
break;
case BetterEnum::enumvalue2:
std::cout << BetterEnum::EnumValue2.getStringVal() << std::endl;
break;
case BetterEnum::enumvalue3:
std::cout << BetterEnum::EnumValue3.getStringVal() << std::endl;
break;
default:
;
}
std::cout << BetterEnum::EnumValue1 << std::endl;
- Выполнение поиска по перечислению на основе строки.
//! Lookup Enum by <code>aStringVal</code>.
static BetterEnum valueOf(const std::string_view aStringVal) {
for (const auto& rNext : getValues()) {
if (rNext.getStringVal() == aStringVal) {
return rNext;
}
}
throw std::invalid_argument(
std::string("Illegal Argument: ") + std::string(aStringVal));
}
- Выполнение поиска по перечислению на основе значения.
//! Lookup Enum by <code>aValue</code>.
static BetterEnum valueOf(const Value aValue) {
for (const auto& next : getValues()) {
if (next.mValue == aValue) {
return next;
}
}
throw std::invalid_argument(
std::string("Illegal Argument: ") + std::to_string(aValue));
}
- Реализация только в качестве заголовка.
Я недавно добавил поддержку для этого, используя встроенные инициализаторы const в нижней части класса.
inline const BetterEnum BetterEnum::EnumValue1(BetterEnum::enumvalue1, "EnumValue1"sv);
inline const BetterEnum BetterEnum::EnumValue2(BetterEnum::enumvalue2, "EnumValue2"sv);
inline const BetterEnum BetterEnum::EnumValue3(BetterEnum::enumvalue3, "EnumValue3"sv);
- добавить поддержку constexpr.
Хотя частично добавлено - использование std::set<T>
ограничивает число членов, которые я могу сделать constexpr, так как для этого потребуется, чтобы std :: set был constexpr (это не так, хотя std::array<T, N>
есть, но это не гарантирует уникальность записей emum, упорядоченных через строго слабый порядок черезоператор operator<()
).
В моем оригинальном дизайне non-constexpr использовались строки - мне пришлось изменить их на string_views для конструктора constexpr - однако я не уверен, как избежать using namespace std::literals;
в заголовочном файлечтобы избежать загрязнения пространства имен для каждого файла, содержащего этот заголовок.
- добавлена поддержка оператора вставки потока.
friend std::ostream& operator<<(std::ostream& os, const BetterEnum& rhs) {
os << rhs.getStringVal();
return os;
}
Мы перешли на несколько лет ив настоящее время на C ++ 17 с C ++ 20 маячит на горизонте.Я хотел посмотреть, смогу ли я улучшить класс, который я затягивал в различных проектах на протяжении многих лет.
В частности, я хотел бы знать, есть ли какой-нибудь способ сделать статические члены constexpr.В C ++ 17 введено понятие улучшенной инициализации статической переменной .Это позволило мне улучшить класс до реализации только заголовка, однако, если я попытаюсь инициализировать статические члены класса внутри определения класса
class BetterEnum final {
public:
enum Value {
enumvalue1, enumvalue2, enumvalue3
};
static constexpr BetterEnum EnumValue1 = BetterEnum(BetterEnum::enumvalue1, "EnumValue1"sv);
static constexpr BetterEnum EnumValue2 = BetterEnum(BetterEnum::enumvalue2, "EnumValue2"sv);
static constexpr BetterEnum EnumValue3 = BetterEnum(BetterEnum::enumvalue3, "EnumValue3"sv);
...
}
, я получаю следующие ошибки:
main.cpp:15:95: error: invalid use of incomplete type 'class BetterEnum'
static constexpr BetterEnum EnumValue1 = BetterEnum(BetterEnum::enumvalue1, "EnumValue1"sv);
^
main.cpp:9:7: note: definition of 'class BetterEnum' is not complete until the closing brace
class BetterEnum final {