[英]Abbreviate argument to member function expecting introduced type (enum class)
TL; DR以下代碼中的成員函數( field_inst.write(decltype(field_inst)::Type::cpr1_4096);
)的enum類類型參數是否有較短的語法?
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);
}
免責聲明:問題本身是重復的: 在成員函數參數中使用嵌套枚舉類時如何防止類限定 。
但是我想知道自2016年(問題日期)/ C ++ 11以來是否有所改進,這將使庫更易於使用(語法更令人愉快)。
此答案中提出的解決方案旨在滿足最初的需求:編寫更短但更富表現力的客戶端代碼。 在這樣做時,我將竭盡所能。 對我來說,最好的行為是利用聲音的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的演示。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.