Добавление c ++ 17 constexpr и других улучшений в эмулятор C ++ Java Enum - PullRequest
3 голосов
/ 21 мая 2019

Пару лет назад я задал вопрос , используя пример для имитации богатого 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 {
...