Отказ от ответственности
Решение, представленное в этом ответе, предназначено для удовлетворения первоначальной потребности: написание более короткого, но выразительного клиентского кода.При этом я пойду на большие ненужные длины.Для меня рекомендуемым поведением является использование звуковых using
объявлений, таких как:
int main() {
using Hal::Aeat_8800_Q24::Cpr_Setting1;
// Or if enums are alone and well encapsulated in their namespace:
//using namespace Hal::Aeat_8800_Q24;
Hal::Bit_Field<reg<0x8FA>, 0x0, 0x7, Cpr_Setting1>
field_int;
field_int.write(Cpr_Setting1::cpr1_4096);
// ...
}
Решение по избыточному количеству ресурсов
Вы можете разработать (очень усиленное) решение на основе пользовательскихлитералы.
// This is just a little helper for later
namespace literals {
template <typename T, T... Cs>
constexpr auto operator ""_as_iseq() {
return std::integer_sequence<T, Cs...>{};
}
}
Затем начинается самое интересное.Объявите класс черты, подобный этому, вместе с псевдонимом помощника:
// Inside namespace Hal::Aeat_8800_Q24
template <typename T> struct setting_enum;
template <typename T>
using setting_enum_t = typename setting_enum<T>::type;
Затем специализируйте его для каждого из ваших перечислений:
// (Still) Inside namespace Hal::Aeat_8800_Q24
using namespace literals;
template <>
struct SettingEnum<decltype("Cpr_Setting1"_as_iseq)> {
using type = Cpr_Setting1;
};
Наконец, давайте определим последний литеральный оператор
// Inside namespace Hal::Aeat_8800_Q24
namespace settings_literals {
template <typename T, T... Cs>
constexpr auto operator""_s()
-> setting_enum_t<
std::integer_sequence<T, Cs...> >;
}
Теперь ваш код клиента просто должен сделать это:
using namespace Hal::Aeat_8800_Q24::settings_literals;
// ...
field_inst.write(decltype("Cpr_Setting1"_s)::cpr1_4096);
Это все еще довольно долго ... Есть ли способ сделать лучше?Да, действительно ... Вместо того, чтобы использовать вышеописанную черту, давайте вместо этого использовать шаблон переменной.
// In namespace Hal
namespace enum_traits {
using namespace literals;
template <typename Enum, typename ValueIntSeq>
constexpr void *ENUM_VALUE = nullptr;
template <>
constexpr Aeat_8800_Q24::Cpr_Setting1 ENUM_VALUE<
Aeat_8800_Q24::Cpr_Setting1, decltype("cpr1_4096"_as_iseq)> =
CprSetting1::cpr1_4096;
// ...
} // ns enum_traits
Шаблон переменной должен быть специализирован для каждого значения каждого перечисления (это утомительно! Я брошу свою шляпулюбому, кто может делать приемы препроцессора, чтобы избежать написания всего этого стандартного кода вручную)
Давайте добавим перегрузку к функции записи члена:
struct BitField : Tregister {
// ...
template <typename T, T... Cs>
void write(std::integer_sequence<T, Cs...> s) {
constexpr auto v_ = enum_traits::ENUM_VALUE<Type, decltype(s)>;
static_assert(
!std::is_pointer_v<decltype(v_)>,
"Invalid enum int sequence provided");
write(v_);
}
};
В конце код клиента будетвыглядеть так:
field_int.write("cpr1_4096"_as_iseq);
Теперь мы говорим!Демо на Coliru .