【问题标题】:How to specialize a templated class's member struct如何专门化模板类成员结构
【发布时间】:2019-04-26 05:37:22
【问题描述】:

假设我有以下模板类:

template<typename T>
class Foo {
    struct store_t {
        uint8_t data[];
    } store;
    /// other stuff using T
}

有没有办法构造一个专门的内部结构版本,相当于这样的东西:

class Foo {
    struct store_t {
        uint16_t f1;
        uint16_t f2;
    } store;
    /// other stuff using T
}

我宁愿保持大多数“使用 T 的其他东西”不专业。不过,我会专门研究一些访问器。 我觉得我想写一些类似的东西

template<>
struct store_t {
    uint16_t f1;
    uint16_t f2;
} Foo<someT>::store;

但这当然行不通。

【问题讨论】:

  • 对内部结构类型使用另一个模板参数,即template &lt;typename T, typename TInternal&gt; class Foo

标签: c++ templates template-specialization


【解决方案1】:

与生活中的大多数事情一样,“如何解决我在使用模板时遇到的这个问题”的答案是“使用更多模板”。

解决方案 1 - 将 store_t 写为模板

谢天谢地,我们不必做任何疯狂的事情。让我们在Foo之外写store_t作为模板:

template<bool use_uint8>
struct Foo_store_t {
    uint8_t data[]; 
};
template<>
struct Foo_store_t<false> {
    uint16_t f1;
    uint16_t f2;
};

现在,在编写Foo 时,我们可以通过测试一些条件来选择我们想要使用的那个:

template<class T>
class Foo {
    constexpr static bool use_uint8 = /* stuff */; 
    using store_t = Foo_store_t<use_uint8>; 
    store_t store;
};

解决方案2——写两个版本的store_t,使用std::conditional

这个也很简单。 std::conditional 允许您使用布尔值在两种不同(任意)类型之间进行选择。

struct store_A {
    uint8_t data[];
};
struct store_B {
    uint16_t f1;
    uint16_t f2;
};
class Foo {
    constexpr static bool useVersionA = /* stuff */; 
    using store_t = std::conditional_t<useVersionA, store_A, store_B>; 
};

这里我使用的是std::conditional_t,它出现在 C++14 中,但如果你仅限于使用 C++11,那就这样做吧:

class Foo {
    constexpr static bool useVersionA = /* stuff */; 
    using store_t = typename std::conditional<useVersionA, store_A, store_B>::type; 
};

【讨论】:

    【解决方案2】:

    只是为了好玩,我展示了另一种基于自我继承的可能解决方案。

    假设您想将Foo 专门用于bool 类型。

    您可以编写主要的Foo,添加一个具有默认值的模板非类型参数(比如一个默认值为truebool

    template <typename T, bool = true>
    struct Foo
     {
        struct store_t
         { std::uint8_t data[10]; }   store;
    
        /// other stuff using T
        T value;
     };
    

    我已添加 T value 作为“使用 T 的其他东西”的示例。

    现在您可以专门化 Foo&lt;bool&gt; 继承自 Foo&lt;bool, false&gt;

    template <>
    struct Foo<bool> : public Foo<bool, false>
     {
        struct store_t
         { std::uint16_t f1, f2; }   store;
     };
    

    这样你可以专门化store_t/store(和其他成员,如果你愿意)从Foo&lt;bool, false&gt;继承“使用T的其他东西”(例如bool value)。

    以下是完整的编译示例

    #include <cstdint>
    #include <type_traits>
    
    template <typename T, bool = true>
    struct Foo
     {
        struct store_t
         { std::uint8_t data[10]; }   store;
    
        T value;
     };
    
    template <>
    struct Foo<bool> : public Foo<bool, false>
     {
        struct store_t
         { std::uint16_t f1, f2; }   store;
    
        // inherits a bool value from Foo<bool, false>
     };
    
    int main()
     {
       Foo<int>   fi;
       Foo<bool>  fb;
    
       static_assert( std::is_same<decltype(fi.value),
                                   int>::value, "!");
       static_assert( std::is_same<decltype(fi.store.data),
                                   std::uint8_t[10]>::value, "!");
       static_assert( std::is_same<decltype(fb.value),
                                   bool>::value, "!");
       static_assert( std::is_same<decltype(fb.store.f2),
                                   std::uint16_t>::value, "!");
     }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-02-20
      • 1970-01-01
      • 1970-01-01
      • 2016-05-03
      • 2021-06-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多