Подтвердить что ты не робот

Эквивалент "использования пространства имен X" для областей с нумерацией?

Я использую enumed scope для перечисления состояний в некоторой машине состояний, которую я реализую. Например, скажем что-то вроде:

enum class CatState
{
    sleeping,
    napping,
    resting
};

В моем файле cpp, где я определяю таблицу перехода состояния, я хотел бы использовать что-то эквивалентное using namespace X, так что мне не нужно префикс всех моих имен состояний CatState::. Другими словами, я бы хотел использовать sleeping вместо CatState::sleeping. В моей таблице переходов есть несколько столбцов, поэтому избегать префикса CatState:: будет держать вещи более компактными и читаемыми.

Итак, есть ли способ избежать необходимости набирать CatState:: все время?


Да, да, я уже знаю о подводных камнях using namespace. Если есть эквивалент для строго типизированных перечислений, я обещаю использовать его только в ограниченной области действия в файле реализации cpp, а не для зла.

4b9b3361

Ответ 1

Итак, есть ли способ избежать необходимости вводить CatState:: все время?

Нет. Точно так же, как нет эквивалента для ввода ClassName:: для статических членов класса. Вы не можете сказать using typename ClassName, а затем попасть во внутренности. То же самое относится к строго типизированному enum s.

Конечно, вы не можете использовать синтаксис enum class, просто используя обычный enum s. Но тогда вы теряете сильную типизацию.

Следует отметить, что одна из причин использования ALL_CAPS для слабо типизированных перечислений заключалась в том, чтобы избежать конфликтов имен. После того, как мы получим полный охват и сильную типизацию, имя перечисления однозначно идентифицируется и не может конфликтовать с другими именами. Возможность ввода этих имен в область пространства имен могла бы вновь ввести эту проблему. Таким образом, вы, скорее всего, захотите снова использовать ALL_CAPS, чтобы помочь устранить эти имена.

Ответ 2

Поэтому короткий ответ - нет, но, к счастью, это изменится в недавно завершенном наборе функций С++ 20. В соответствии с этим принятым предложением вы сможете выполнять следующие действия:

enum class CatState
{
    sleeping,
    napping,
    resting
};

std::string getPurr(CatState state)
{
    using enum CatState;
    // our states are accessible without the scope operator from now on

    switch (state)
    {
        case sleeping:      return {};      // instead of "case CatState::sleeping:"
        case napping:       return "purr";
        case resting:       return "purrrrrr";
    }
}

Ответ 3

Вы можете использовать typedef для сокращения квалифицированных имен:

typedef CatState C;

Или, если столбцы повторяются так, что их можно легко сгенерировать, вы можете использовать макрос для генерации каждой строки в таблице, что может привести к очень краткому (и более легко читаемому) коду.

Ответ 4

Ответ Nicol правильный: язык предназначен для того, чтобы вы всегда квалифицировали счетные счетчики (кроме самой области enum { }).

Однако вот техника. Я придумал для "подсвеченных" счетчиков, которые не облагаются в выбранных классах. Технически перечисления не облагаются, поэтому они все равно будут неявно преобразовываться в int. (Не "сильно типизировано", как вы выразились.) Тем не менее, в идиоме к ним обращаются с помощью оператора области видимости после истинного имени enum, поэтому синтаксически нет разницы - и поэтому для этого требуется С++ 11.

#define IMPORTABLE_ENUM( TYPENAME, ... ) \
\
struct import_ ## TYPENAME { \
    enum TYPENAME { \
        __VA_ARGS__ \
    }; \
}; \
\
typedef import_ ## TYPENAME :: TYPENAME TYPENAME;

// usage:
IMPORTABLE_ENUM ( duck, huey, dewey, louie )

duck d = duck::dewey; // can't use unscoped enumerators here

struct duck_madness : private import_duck { // but inside a derived class
    duck who_did_it() { return huey; } // qualification is unnecessary
};

Ответ 5

Я тоже хотел бы иметь такую ​​возможность, и я нахожу ограничение довольно раздражающим. Обычно лучше всего, чтобы программист решил, какие функции он хочет использовать. Либо явный обзор, либо более удобный способ. Если вы ограничите программиста, он либо сбросит всю функцию ради удобства, либо изобретает уродливые обходные пути, например, следующее безопасное перечисление типа на основе шаблонов. Он будет иметь некоторые накладные расходы при компиляции без оптимизации.

template<class _Enum>
class type_safe_enum
{
private:
    _Enum m_EnumValue;
    operator int();
public:
    inline operator _Enum() const { return m_EnumValue; }
    inline void operator =(_Enum x) { m_EnumValue = x; }
};

enum _MY_ENUM
{
    Value1,
    Value2
};

enum _MY_ENUM2
{
    Value3,
    Value4
};

typedef type_safe_enum<_MY_ENUM> MY_ENUM;

void TestMyEnum()
{
    MY_ENUM myEnum;
    int x;

    myEnum = Value1; // ok
    // myEnum = Value3; // compilation error
    // myEnum = 0; // compilation error
    // x = myEnum; // compilation error

}