Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Zero-sized member variable in templated struct

Tags:

c++

templates

I have a templated struct that has a variant with an extra float, like this:

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

To save memory (yes it is significant) I'd like to omit that float if HasFloat is false. Since there is a lot of other stuff in the struct the best way would be something like this:

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

Except there is no such thing as a zero sized type in C++ as far as I can tell. The only exception seems to be "Flexible Array Members", so I could maybe do something like this:

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

Except they are only supported in C99, not C++.

The standard solution to this seems to be to use inheritance, since base classes can be zero-sized, however my struct is also accessed by assembly and to make the assembly simpler it is better if the float b; is at the end of the struct rather than the beginning, and anyway that isn't guaranteed.

So this seems to leave template specialisation as the only option but my class is actually rather long and I'd like to avoid duplicating everything. Is there another solution that I'm missing?

like image 821
Timmmm Avatar asked Oct 08 '18 14:10

Timmmm


1 Answers

One of my colleagues came up with a fairly nice solution. It does require copy & pasting the data members but at least I don't have to duplicate my methods.

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

You could do:

  struct StateWithFloat {
    State state;
    float k;
  };

But then you have to add template functions to avoid the state.a vs state.state.a problem and copy & pasting seems easier at that point.

Also @aschepler pointed out that in C++20 you will be able to use [[no_unique_address]].

like image 129
Timmmm Avatar answered Oct 18 '22 22:10

Timmmm