缩写对成员函数期望引入类型(ENUM类)的论点

Abbreviate argument to member function expecting introduced type (enum class)

本文关键字:ENUM 类型 成员 函数 期望 缩写      更新时间:2023-10-16

tl; dr 在以下代码中,eNum类类型参数( field_inst.write(decltype(field_inst)::Type::cpr1_4096);)是否有较短的语法?

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