0
votes

I have tried union...

struct foo
{
    union
    {
        struct // 2 bytes
        {
            char var0_1;
        };
        struct // 5 bytes
        {
            char var1_1;
            int var1_2;
        };
    };
};

Problem: Unions do what I want, except they will always take the size of the biggest datatype. In my case I need struct foo to have some initialization that allows me to tell it which structure to chose of the two (if that is even legal) as shown below.

So after that, I tried class template overloading...

template <bool B>
class foo { }

template <>
class foo<true>
{
    char var1;
}

template <>
class foo<false>
{
    char var0;
    int var1;
}

Problem: I was really happy with templates and the fact that I could use the same variable name on the char and int, but the problem was the syntax. Because the classes are created on compile-time, the template boolean variable needed to be a hardcoded constant, but in my case the boolean needs to be user-defined on runtime.

So I need something of the two "worlds." How can I achieve what I'm trying to do?

!!NOTE: The foo class/struct will later be inherited, therefore as already mentioned, size of foo is of utmost importance.

EDIT#1:: Application:

Basically this will be used to read/write (using a pointer as an interface) a specific data buffer and also allow me to create (new instance of the class/struct) the same data buffer. The variables you see above specify the length. If it's a smaller data buffer, the length is written in a char/byte. If it's a bigger data buffer, the first char/byte is null as a flag, and the int specifies the length instead. After the length it's obvious that the actual data follows, hence why the inheritance. Size of class is of the utmost importance. I need to have my cake and eat it too.

3
What is it you are trying to accomplish?NathanOliver
Perhaps you can look into boost::any?AndyG
@NathanOliver I will use it as a pointer to read/write data, and initialize an instance of it to write new data. foo will be more of a shared interface.Hello World
Best bet is to use the Macro's __x86_64__ and the like, or to check via UINTPTR_MAX if it is the size is a 64 bit long size, or 32 bit size long. Then use size_t as your member type. That should guarantee it's the size of a pointer. Might be a little too much out of the box, or the wrong direction of thinking for what you're trying to do.M4rc

3 Answers

1
votes

A layer of abstraction.

struct my_buffer_view{
  std::size_t size()const{
    if (!m_ptr)return 0;
    if (*m_ptr)return *m_ptr;
    return *reinterpret_cast<std::uint32_t const*>(m_ptr+1);
  }
  std::uint8_t const* data() const{
    if(!m_ptr)return nullptr;
    if(*m_ptr)return m_ptr+1;
    return m_ptr+5;
  }
  std::uint8_t const* begin()const{return data();}
  std::uint8_t const* end()const{return data()+size();}
  my_buffer_view(std::uint_t const*ptr=nullptr):m_ptr(ptr){}
  my_buffer_view(my_buffer_view const&)=default;
  my_buffer_view& operator=(my_buffer_view const&)=default;
private:
  std::uint8_t const* m_ptr=0;
};

No variable sized data anywhere. I coukd have used a union for size etx:

  struct header{
    std::uint8_t short_len;
    union {
      struct{
        std::uint32_t long_len;
        std::uint8_t long_buf[1];
      }
      struct {
        std::short_buf[1];
      }
    } body;
  };

but I just did pointer arithmetic instead.

Writing such a buffer to a bytestream is another problem entirely.

0
votes

Your solution does not make sense. Think about your solution: you could define two independents classes: fooTrue and fooFalse with corresponding members exactly with the same result.

Probably, you are looking for a different solution as inheritance. For example, your fooTrue is baseFoo and your fooFalse is derivedFoo with as the previous one as base and extends it with another int member.

In this case, you have the polymorphism as the method to work in runtime.

0
votes

You can't have your cake and eat it too.

The point of templates is that the specialisation happens at compile time. At run time, the size of the class is fixed (albeit, in an implementation-defined manner).

If you want the choice to be made at run time, then you can't use a mechanism that determines size at compile-time. You will need a mechanism that accommodates both possible needs. Practically, that means your base class will need to be large enough to contain all required members - which is essentially what is happening with your union based solution.

In reference to your "!!NOTE". What you are doing qualifies as premature optimisation. You are trying to optimise size of a base class without any evidence (e.g. measurement of memory usage) that the size difference is actually significant for your application (e.g. that it causes your application to exhaust available memory). The fact that something will be a base for a number of other classes is not sufficient, on its own, to worry about its size.