简体   繁体   English

如何专门化模板类的成员结构

[英]How to specialize a templated class's member struct

Say I have the following templated class: 假设我有以下模板类:

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

Is there a way to construct a specialized version of the internal struct that would equate to something like this: 有没有办法构建一个内部结构的专用版本,等同于这样的东西:

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

I would prefer to keep most of the "other stuff using T" unspecialized. 我宁愿保留大部分“使用T的其他东西”非专业化。 I would specialize some accessors though. 我会专门研究一些访问者。 I feel I would want to write something like 我觉得我想要写一些类似的东西

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

but that of course doesn't work. 但那当然不行。

As with most things in life, the answer to "how do I solve this problem I'm having with templates" is "use more templates." 与生活中的大多数事情一样,“如何通过模板解决这个问题”的答案是“使用更多模板”。

Solution 1 - write store_t as a template 解决方案1 ​​ - 将store_t写为模板

Thankfully, we don't have to do anything crazy. 值得庆幸的是,我们不必做任何疯狂的事情。 Let's write store_t outside of Foo as a template: 让我们写store_t之外Foo作为模板:

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

Now, when writing Foo , we can just pick which one we wanna use by testing some condition: 现在,在编写Foo ,我们可以通过测试某些条件来选择我们想要使用的那个:

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

Solution 2 - write two versions of store_t , use std::conditional 解决方案2 - 编写store_t两个版本,使用std::conditional

This one is also pretty straight-forward. 这个也非常简单。 std::conditional lets you pick between two different (arbitrary) types using a boolean. 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>; 
};

Here I'm using std::conditional_t , which appears in C++14, but if you're restricted to using C++11 just do: 这里我使用的是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; 
};

Just for fun, I show another possible solution based over a sort of self-inheritance. 为了好玩,我展示了一种基于某种自我继承的可能解决方案。

Suppose you want specialize Foo for the type bool . 假设你想为bool类型使用specialize Foo

You can write the main Foo adding a template non-type parameter with a default value (say a bool with a default value of true ) 您可以编写主Foo添加一个带有默认值的模板非类型参数(比如一个默认值为truebool

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

    /// other stuff using T
    T value;
 };

I've added T value as example of "other stuff using T". 我添加了T value作为“使用T的其他东西”的例子。

Now you can specialize Foo<bool> inheriting from Foo<bool, false> 现在,你可以专注Foo<bool>继承Foo<bool, false>

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

This way you can specialize store_t / store (and other members, if you want) inheriting from Foo<bool, false> the "other stuff using T" (a bool value , by example). 这样你就可以专门化store_t / store (以及其他成员,如果你愿意的话)继承自Foo<bool, false> “使用T的其他东西”( bool value ,例如)。

The following is a full compiling example 以下是完整的编译示例

#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, "!");
 }

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

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