问题
TL;DR Is there a Shorter syntax for the enum class type argument to a member function (field_inst.write(decltype(field_inst)::Type::cpr1_4096);
) in the following code?
namespace Hal {
// complex template definition `Bit_Field`
template<
class Tregister,
typename Tregister::Data Toffset,
typename Tregister::Data Tmask,
class Tfield_type,
class Tmutability_policy = typename Tregister::Mutability_Policy
>
struct Bit_Field : Tregister {
using Type = Tfield_type;
static Field read()
{ // ... reading ...
}
};
namespace Aeat_8800_Q24 {
enum class {cpr1_4096 = 0x5,
// ... more settings ...
};
} // namespace Aeat_8800_Q24
} // namespace HAl
int main(void) {
// this template is used multiple times, different template arguments
// on each instantiation (using / typedef not practical)
Hal::Bit_Field<reg<0x8FA>, 0x0, 0x7, Hal::Aeat_8800_Q24::Cpr_Setting1>
field_inst;
// QUESTION: How can I write that more pleasingly?
field_inst.write(decltype(field_inst)::Type::cpr1_4096);
field_inst.write(Hal::Aeat_8800_Q24::Cpr_Setting1::cpr1_4096);
}
Disclaimer: The question itself is a duplicate to: How to prevent class qualification when using nested enum class in member function arguments.
However I want to know if there has been improvements since 2016 (date of question) / C++11 which would make the library easier to use (more pleasant syntax).
回答1:
Disclaimer
The solution presented in this answer intends to answer the original need: writing shorter yet expressive client code. In doing so, I will go to great unnecessary lengths. To me, the advisable behavior is the the use of sound using
declarations such as:
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);
// ...
}
Overkill solution
You can devise a (very overengineered) solution based on user-defined literals.
// 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...>{};
}
}
Then, the fun begins. Declare a trait class like this, along with its helper alias:
// Inside namespace Hal::Aeat_8800_Q24
template <typename T> struct setting_enum;
template <typename T>
using setting_enum_t = typename setting_enum<T>::type;
Then, specialize it for each of your enums:
// (Still) Inside namespace Hal::Aeat_8800_Q24
using namespace literals;
template <>
struct SettingEnum<decltype("Cpr_Setting1"_as_iseq)> {
using type = Cpr_Setting1;
};
Finally let's define a last literal operator
// 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...> >;
}
Now your client code just needs to do this:
using namespace Hal::Aeat_8800_Q24::settings_literals;
// ...
field_inst.write(decltype("Cpr_Setting1"_s)::cpr1_4096);
That's still quite long... Is there a way to do better? Yes indeed... Instead of using the trait above let's use a variable template instead.
// 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
The variable template needs to be specialized for each value of each enum (that's tedious! I'll throw my hat to anyone that can do preprocessor tricks to avoid writing all that boilerplate code by hand)
Let's add an overload to the write member function:
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_);
}
};
In the end, the client code will look like this:
field_int.write("cpr1_4096"_as_iseq);
Now we're talking! Demo on Coliru.
来源:https://stackoverflow.com/questions/54874432/abbreviate-argument-to-member-function-expecting-introduced-type-enum-class