【问题标题】:Pair a non-type with each type in variadic templates将非类型与可变参数模板中的每种类型配对
【发布时间】:2023-04-02 17:25:01
【问题描述】:

有什么方法可以让我拥有可变参数对吗?我的目标是为每种类型添加额外的信息。

类似这样的:

// non compilable code

// I want to pass an extra uint8_t with each type here.
template<template<typename EnumType, uint8_t Bitmask> typename... EnumsAndBitmasks>
void func(){
    // Unpack EnumsAndBitmasks and do something with pairs of each EnumType and it's Bitmask
}

// Call func like this
enum class Type1 : uint8_t;
enum class Type2 : uint8_t;
enum class Type3 : uint8_t;

func<<Type1,0x03>, <Type2,0x3C>, <Type3,0xC0>>();

以下是非模板化的工作代码,但我想通过提供返回结构类型和每个 EnumType 及其位掩码作为unpack_from_single_byte 函数的模板参数来概括这个过程。

enum class EnumType1 : uint8_t { first, second };
enum class EnumType2 : uint8_t { first, second, third, forth };
enum class EnumType3 : uint8_t { first, second };

struct Unpacked
{
    EnumType1 var1;
    EnumType2 var2;
    EnumType3 var3;
};

Unpacked unpack_from_single_byte(uint8_t value)
{
        return { static_cast<EnumType1>(value & 0x01), 
                 static_cast<EnumType2>(value & 0x06), 
                 static_cast<EnumType3>(value & 0x0F) };
}

【问题讨论】:

    标签: c++ templates variadic-templates


    【解决方案1】:

    您可以添加一个间接级别。首先,引入一个标签:

    template<class T, std::uint8_t v> struct Tag {
        using Type = T;
        static constexpr std::uint8_t value = v;
    };
    

    然后写:

    template<class... Tags>
    void func() { /* ... */ }
    
    func<Tag<Type1, 0x03>, Tag<Type2, 0x3C>, Tag<Type3, 0xC0>>();
    

    您可以通过成员Typevalue提取Tv。例如:

    template<class... Tags>
    void func() {
        std::tuple<typename Tags::Type...> tuple;
        std::uint8_t values[] = {Tags::value...};
    }
    

    编辑。如果我的概括正确,你可能想要这样的东西:

    template<class... Tags>
    std::tuple<typename Tags::Type...> unpack_from_single_byte(std::uint8_t value) {
        return std::tuple<typename Tags::Type...>{
            static_cast<typename Tags::Type>(Tags::value & value)...};
    }
    
    ... = unpack_from_single_byte<
        Tag<Type1, 0x03>, Tag<Type2, 0x3C>, Tag<Type3, 0xC0>>(0x20);
    

    这个函数返回一个std::tupleUnpacked的泛化),每个成员都等于Tag::value &amp; value,其中value是函数参数。

    没有Tags 的替代语法可能是:

    template<class... Enums, typename... Bitmasks>
    std::tuple<Enums...> unpack_from_single_byte(std::uint8_t value, Bitmasks... bitmasks) {
        static_assert(sizeof...(Enums) == sizeof...(Bitmasks));
        return std::tuple<Enums...>{static_cast<Enums>(value & bitmasks)...};
    }
    
    ... = unpack_from_single_byte<Type1, Type2, Type3>(0x20, 0x03, 0x3C, 0xC0);
    

    【讨论】:

    • 完美,这就是我的想法,有什么办法可以消除调用站点中的标签结构吗?
    • @ashtum,如果您想将枚举和 uint 一起作为模板参数,我想不会。如果你放宽这个要求,你有一些选择。例如,您可以将 uint 移动到函数参数中并编写如下内容:unpack_from_single_byte&lt;Type1, Type2, Type3&gt;(value, 0x03, 0x3C, 0xC0) 然后检查枚举和 uint 的数量是否匹配。
    猜你喜欢
    • 2019-09-01
    • 2015-11-26
    • 2017-10-31
    • 2020-12-15
    • 1970-01-01
    • 2019-04-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多