简体   繁体   English

成员函数的缩写参数,期望引入类型(枚举类)

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

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? 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);
}

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). 但是我想知道自2016年(问题日期)/ C ++ 11以来是否有所改进,这将使库更易于使用(语法更令人愉快)。

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: 对我来说,最好的行为是利用声音的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);
    // ...
}

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 . 关于Coliru的演示。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM