Generate a C++ class from an other one

113 views Asked by At

I want to generate class Y from class X :

class X{

  T e;
  optional<T1> e1;
  optional<T2> e2;
  optional<T3> e3;
  T4 e4;

  // Member functions
  ...
};

class Y{ 
  T  e;
  T1 e1;
  T2 e2;
  T3 e3;
  T4 e4;
  bool b1;
  bool b2;
  bool b3;

  // Member functions
  ...
}

So, basically I want to put the booleans of optional at the end to win some memory, (this is called packing) You can assume that the member functions doesn't use any optional, so the generated code would be correct, also the class can have as many optionals as possible

I know that there is no class reflexion in C++, but with Variadic Templates, it seems we can do some awsome stuff.

I have been thinking about a solution for this issue using them , but I couldn't find any. I thought someonse else may have tried something like this.

EDIT : The main goal of this is to reduce the memory of the first class, by putting the booleans of optional at the end (reducing padding), derivation won't do this, since the size of the derived class would be greater than base class

The code would be generated either by passing the class X as template to a generator ClassGenerator<X>, or maybe the generator can take more arguments like this ClassGenerator<X, T1, T2, T3>

1

There are 1 answers

3
Potatoswatter On BEST ANSWER

So, basically I want to put the booleans of optional at the end to win some memory,

The best way to reclaim memory is to declare them as bitfields, or to do equivalent bitwise arithmetic manually.

The problem can be solved by using variadic templates and bitwise arithmetic. To aggregate the members you can use std::tuple, and to aggregate the bits use std::bitset. From there, you can make an accessor that returns an optional by value.

You can assume that the member functions doesn't use any optional, so the generated code would be correct

There are no member functions there.

You might be overestimating the freedom that C++ gives you in typecasting. You cannot cast X* to Y*, for example. Not by a long shot. (At least, not if you use the Y* result.)


Really, the hard part is that you don't have optional any more and you need to reinvent it. So then you need some kind of union, but individually the unions don't know how to move or destroy themselves, because they need that bit. So you can't put them inside a tuple, so then you need to reinvent tuple as well.

template< typename t >
union storage {
    t value;

    storage() {} // uninitialized
    storage( t in ) : value( std::move( in ) ) {}
    // Impossible to define the copy/move constructor.

    ~ storage() // Impossible to define. Destroy value or not?
};

template< typename ... elem >
class optional_tuple {
    std::tuple< storage< elem > ... > e
    std::bitset< sizeof ... (elem) > b;

    optional_tuple( std::optional< elem > ... v )
        : e{ std::move( v ) ... }
        , b{ (bool) v ... }
        {}
    }
};