Страницы

Поиск по вопросам

среда, 18 декабря 2019 г.

Класс для перечисления с заданным типом C++

#cpp #qt #boost


Если в С++ сделать 

enum operation = {plus, minus, mult, div};


То перечисляемые константы буду иметь тип operation.

А если мне нужно, чтобы переменная operation была типа char, и могла принимать только
значения {'+', '-', '*', '/'} ?

Есть ли в std/Qt/boost/другой библиотеке какой-либо контейнер, который позволяет
делать что-то в духе:

Enumeration operation = {'+', '-', '*', '/'};


Или необходимо писать велосипед самому? Может, что-то есть на эту тему из области
шаблонов проектирования?

Upd:
Или, еще лучше, если перечисляемые значения могут быть разного типа. К примеру, при
разборе строки с арифметическим выражением на токены, токен может быть типов Operator,
Operand или Bracket. Как-то так:

Enumeration Token = {op, num, br};

    


Ответы

Ответ 1



Нет, ни в C++, ни в boost&Qt такого контейнера нет. Нет его по одной простой причине — в C++ нет одного общего типа как, скажем в C#&Java. Поэтому, просто невозможно создать контейнер, который будет принимать разнородные данные. Можно, конечно, создать std::vector(QList и вариации) но это, мягко говоря, не лучшее решение, т.к. всё равно придётся «помнить», что там за данные, иначе извлечь их не получится. Поэтому, такие задачи решаются введением одного общего предка, а все вариации являются его наследниками. Создаётся контейнер указателей на этого предка и в него помещаются нужные потомки. К примеру, у Вас может быть std::vector> vec; и в него Вы будете помещать Ваши конкретные объекты: vec.push_back(std::make_shared()); Но лучше это всё вынести в ещё одну абстракцию, которая будет представлять собой контейнер, а не использовать «голый» вектор. Вообще, это довольно обширная тема, которую в рамках ответа не так просто и раскрыть. Но если просто взять Ваш пример из вопроса, то его можно легко написать так: std::tuple Token = std::make_tuple(op, num, br); Хотя, я полагаю, Вам всё же нужен будет более широкий функционал и динамизм, который не достижим с помощью std::tuple. Если моё предположение верно, то для Вас подходит первая часть ответа.

Ответ 2



Вашу проблему касательно char можно решить достаточно просто: хранить коды символов в самом enum'e (ведь базовым типом перечисления может быть любой целочисленным тип, т.е. int, long, char и некоторые другие), а затем при обращении к элементам перечисления делать явное приведение к char: enum CharEnum: char { plus = '+', minus = '-', mult = '*', div = '/' }; int main() { std::cout << static_cast(CharEnum::plus); } Стоит заметить, что начиная с C++11 появился enum class (можно писать и enum struct, что то же самое), который обладает рядом преимуществ перед обычным enum: не экспортирует свои значения в окружающую область видимости, что могло бы приводить к конфликтам имен отсутствует неявное преобразование значений перечислимого типа к целочисленным типам как у обычного enum, что могло бы приводить к ошибкам Таким образом, в предыдущем примере достаточно поменять enum на enum class, а весь остальный синтаксис останется неизменным.

Комментариев нет:

Отправить комментарий