У меня есть класс перечисления, я пытаюсь создать функцию, которая будет возвращать строку соответствующего члена класса перечисления.
Например, если у меня есть следующий класс перечисления:
enum class SignalState
{
red, // 0
yellow, // 1
green, // 2
max_num
};
Я хотел бы вернуть строки «красный», «желтый» или «зеленый», в зависимости от члена SignalState, который я передаю в функцию.
В C это довольно просто, но в C++ у меня возникли некоторые трудности с тем, как это сделать.
Для этой задачи я использую std::string_view
и std::array
.
Вот мой код:
#include <iostream>
#include <string>
#include <string_view>
#include <array>
// Scoped enumerators (enum class) unlike unscoped enumerators (enum)
// won't explicitly convert to integers; you have to cast them, as we did on "signal_string" function
enum class SignalState //scoped enumerators return the Type member
{
red, // 0
yellow, // 1
green, // 2
max_num
};
//using C arrays:
/*
static const char* signal_string(SignalState signal) //this takes an enum as paramenter and returns the matching string
{
static const char *ss[] = {"Red","Yellow","Green"};
return ss[ static_cast<unsigned>(signal) ]; //converts enum class "Type" into an unsigned integer, with enum classes as opposed to enum you gotta expliclty convert it
}
*/
//using C++:
static const std::string_view signal_string(SignalState signal)
{
static const std::array <SignalState, SignalState::max_num> ss {"Red","Yellow","Green"};
return ss[ static_cast<unsigned>(signal) ];
}
int main()
{
SignalState mysig{SignalState::red};
std::cout << "Color is: " << signal_string(mysig);
return 0;
}
Ошибка:
error: value of type 'SignalState' is not implicitly convertible to 'size_t' (aka 'unsigned long')
ОБНОВЛЯТЬ: Статическое приведение SignalState внутри массива:
static const std::array <SignalState, static_cast<unsigned>(SignalState::max_num)> ss {"Red","Yellow","Green"};
Я все еще получаю следующую ошибку:
error: implicit instantiation of undefined template 'std::__1::array<SignalState, 3>'
static const std::array <SignalState, static_cast<unsigned>(SignalState::max_num)> **ss** {"Red","Yellow","Green"};
Любая помощь приветствуется. Я думаю, что должен быть более простой и понятный способ создания этой функции, не может быть, чтобы в C++ это было сложнее сделать, чем в C. Большое спасибо
Этот пост может быть интересен: Как преобразовать перечисление в строку в современном C++.
Одним из обходных путей является использование const std::map
, как показано ниже:
static const std::string_view signal_string(SignalState signal)
{
static const std::map<SignalState, std::string_view> myMap = {{SignalState::red,"Red"},{SignalState::yellow,"Yellow"},{SignalState::green,"Green"}};
return myMap.at(signal);
}
Это кажется излишним. В чем это преимущество перед простым std::array
?
@wohlstad Я предложил одно возможное решение. Не обязательно публиковать только лучшее из возможных решений. Любое работающее решение жизнеспособно и полезно для будущих читателей. Я не понимаю, почему вы всегда без причины критикуете ответы других людей. Не обязательно, чтобы ответ имел какое-то преимущество перед другими публикуемыми ответами. Для будущих читателей приемлемо любое жизнеспособное/работающее решение. В зависимости от ситуации читатели могут выбирать. Чем больше выбора у людей/читателей, тем больше они узнают.
Я редко критикую другие ответы и только тогда, когда считаю, что у меня есть веские аргументы. Я всегда делаю это вежливо и прошу разъяснений. Альтернативные решения полезны только в том случае, если они дают какое-то преимущество, и именно об этом я вас и спрашивал. Вы могли бы просто ответить по существу (чего вы не сделали). Не обвиняйте других в несправедливости без уважительной причины.
@wohlstad Я не думаю, что мне нужно оправдывать публикацию своего ответа, если в нем нет ничего технически неправильного, а также он не повторяет другие ответы.
Вы что-то упускаете. Это не вопрос оправдания. Это была попытка (явно провальная) обсудить преимущества различных решений. Но я вижу, что вас это не интересует, поэтому не буду продолжать.
Таким образом, одно из преимуществ (неупорядоченной) карты перед массивом — широкий диапазон с дырками enum class E{ A= 0, B = 500, C = 2048};
. но (упорядоченный) массив парных перечислений, stringview также выполнит эту работу (против упорядоченной карты).
Вам следует объявить массив std::string_view
, а не массив SignalState
. Альтернативно, вы можете позволить вывести параметры шаблона:
std::string_view signal_string(SignalState signal)
{
using namespace std::string_view_literals;
static const std::array ss { "Red"sv, "Yellow"sv, "Green"sv };
return ss[ static_cast<std::size_t>(signal) ];
}
Вам следует создать массив constexpr
, а не только const
, и он, конечно, требует проверки границ, чтобы гарантировать отсутствие UB.
ss
должен быть массивомstring
(илиstring_view
), а не массивом элементов типа перечисления (SignalState
), поэтомуstd::array<SignalState, ...>
неверно.