模板结构中的零大小成员变量

时间:2018-10-08 14:08:28

标签: c++ templates

我有一个模板化的结构,该结构具有一个带有额外浮点数的变体,如下所示:

template <bool HasFloat>
struct Foo {
   std::vector<int> a;
   float b; // Not needed if HasFloat is false
};

为了节省内存(是的,这很重要),如果HasFloat为false,我想省略float。由于struct中还有很多其他内容,因此最好的方法如下:

using B = typename std::conditional<HasFloat, float, ZeroSizedType>::type;
B b;

据我所知,除了C ++中没有零大小类型的东西。唯一的例外似乎是“ Flexible Array Members”,所以我也许可以这样做:

using B = typename std::conditional<HasFloat, float, float[]>::type;

除了它们仅在C99中受支持,在C ++中不受支持。

对此的标准解决方案似乎是使用继承,因为基类 的大小可以为零,但是我的结构也可以由程序集访问,并且使程序集更简单,如果float b;位于结构的末尾,而不是开头,反之that isn't guaranteed

因此,这似乎让模板专业化成为唯一选择,但我的课实际上很长,我想避免重复所有内容。我还缺少其他解决方案吗?

3 个答案:

答案 0 :(得分:2)

我的一位同事提出了一个相当不错的解决方案。它确实需要复制和粘贴数据成员,但是至少我不必重复我的方法。

template <bool HasFloat>
struct Foo {
  struct State {
    std::vector<int> a;
  };

  struct StateWithFloat {
    std::vector<int> a;
    float k;
  };

  using FooState = std::conditional_t<HasFloat, StateWithFloat, State>;
  FooState state;
};

您可以这样做:

  struct StateWithFloat {
    State state;
    float k;
  };

但是随后您必须添加模板函数以避免state.astate.state.a的问题,此时复制和粘贴似乎更容易。

@aschepler还指出,在C ++ 20中,您将可以使用[[no_unique_address]]

答案 1 :(得分:-2)

您可以创建一个专门针对是否具有float的结构,然后在转发template参数的结构中使用它。像这样:

template <bool HasFloat>
struct PerhapsFloat;

template <>
struct PerhapsFloat<true>
{
    float b;
};

template <>
struct PerhapsFloat<false>
{

};

template <bool HasFloat>
struct Foo {
   std::vector<int> a;
   PerhapsFloat<HasFloat> b;
};

在这里,您有一个演示: https://godbolt.org/z/7zPto9

答案 2 :(得分:-3)

尝试将专业化提取到基类/成员类。

template <bool B>
struct Foo {};

template <>
struct Foo<true>
{
    float f;    
};

template <bool HasFloat>
class Bar 
{
    Foo<HasFloat> b;
};

class Empty {};

int main()
{
    std::cout << sizeof(Bar<true>) << std::endl; // 4
    std::cout << sizeof(Bar<false>) << std::endl; // 1
    std::cout << sizeof(Empty) << std::endl; // 1
}