Variable class/struct structure? (Not template & not union?) - c++

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.

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.

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.

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.

Related

What is the need for MaxAlign trick when creating static singleton?

Following a snippet of code from Loki singleton implementation which shows what it calls "MaxAlign Trick". I assume it has something to do with alignment (duh!), but what's the purpose of trying to align with all the types mentioned inside the union? Will the placement new inside Create() break without it?
template <class T> struct CreateStatic
{
union MaxAlign
{
char t_[sizeof(T)];
short int shortInt_;
int int_;
long int longInt_;
float float_;
double double_;
long double longDouble_;
struct Test;
int Test::* pMember_;
int (Test::*pMemberFn_)(int);
};
static T* Create()
{
static MaxAlign staticMemory_;
return new(&staticMemory_) T;
}
// other code...
}
MaxAlign serves two purposes. First, it is an implementation of the C++11 std::max_align_t: "a trivial standard-layout type whose alignment requirement is at least as strict (as large) as that of every scalar type." (cppreference). Since the alignment of a type is the alignment of the data member with the highest alignment requirements, the definition of MaxAlign gives us exactly that: a type that is guaranteed to have the max. alignment for the platform of interest.
Second, it is also a buffer that is large enough to contain a T:
char t_[sizeof(T)];
Taking both aspects, MaxAlign provides the C++11 feature std::aligned_storage_t<size, alignment> (without taking over-alignment of T is into account - it probably didn't even exist back then).
But why is it needed: placement new requires the buffer to be suitably aligned for the instance that is being constructed. Without this "alignment trick", you might end up with undefined behaviour. T being an unkonwn type, Loki circumvents any risks by choosing the maximal alignment for the platform the code is being compiled for.
In modern code, you would probably not use placement new, but use a static object on the stack, e.g.
static T& Create() {
static T instance;
return instance;
}
But 20 years ago, this might not have worked properly across compilers and/or in multi-threaded environments (proper initialisation of T instance in the above is only guaranteed since C++11 IIRC).

Switching between two typedef structs, depending on boolean

I have a class with different functions. This class uses two typedef structs.
typedef struct {
struct head;
struct data1;
} data_struct_1;
typedef struct {
struct head;
struct data2;
} data_struct_2;
If a bool is true the data_struct_2 should be used, otherwise data_struct_1. The boolean is passed, when the object is created and stored as a membervariable in the constructor.
There are now different functions and declarations like
int calc_mean(data_struct_1 ds, int a){ ... }
or
data_struct_1 ds;
ds.data1 = 5;
Is there an elegant way, which allows me to switch between those two structs without implementing dozens of if-cases and duplicate all the relevant functions with the corresponding struct in the header?
First I was thinking about inheritance and overwritting relevant functions if bool is true.. but the header in the functions differs, so this wouldnt work
Maybe there is something like a placeholder or template, but i'm pretty new to c++
If boolean is compile-time value, std::conditional might be used:
template <boolean B>
using my_type = std::conditional_t<B, data_struct_1, data_struct_2>;
but it seems the boolean is runtime value, so I would use std::variant and std::visit:
class C
{
using Data = std::variant<data_struct_1, data_struct_2>;
Data m_data;
public:
C(bool b) : m_data{b ? Data{data_struct_1{}} : Data{data_struct_2{}}} {}
auto mean() const {
return std::visit([](const auto& data){ return calc_mean(data, 42); }, m_data);
}
};
You have a couple of options:
If the types are conceptually the same type of thing (i.e. they have the same interface and could be substituted for one another), you can:
Create an abstract base type and use polymorphism to change which concrete type is instantiated
Change all places that use these types into templates, change which template(s) are instantiated at runtime, and then rely on compile-time "duck-typing" to do the rest
If the types are conceptually different (i.e. they should not have the same interface), you can use a union type (union, std::variant).
Take a look at std::variant.
A variant can hold a number of alternative types, like this:
std::variant<data_struct_1, data_struct_2> m;
The member m can contain either a data_struct_1 or a data_struct_2. The variant will remember which, so there's no need for you to carry that bool around anymore.
The interesting question is now, how do you treat m in your functions? After all, it could be either a data_struct_1 or a data_struct_2 in there. Instead of using branches for distinguishing these cases, variant uses visit: Whenever you encounter a point in the function that depends on the concrete type stored in m, you move that code into two overloaded functions: One function that handles the data_struct_1 case and another that handles the data_struct_2 case. The example on the visit cppreference page shows some possibilities for doing that with varying degrees of syntactic overhead.
The good thing about this approach is that it forces you to always handle both cases properly. You can't just go ahead and write an implementation for one case and then forget about the other, having it blow up later at runtime. It also encourages a style where you clearly separate common parts of your code from type-specific parts, which often results in a cleaner design in the long term.
One possibility is to use std::variant:
typedef std::variant<data_struct_1, data_struct_2> data_struct_1_or_2;
void foo(data_struct_1_or_2 ds) {
if (auto ds1 = std::get_if<data_struct_1>(&ds)) {
// use ds1, which is type data_struct_1*
} else if (auto ds2 = std::get_if<data_struct_2>(&ds)) {
// use d2, which is type data_struct_2*
} else {
throw std::logic_error("Unexpected value in variant");
}
}
void bar(data_struct_1_or_2 ds) {
foo(ds); // Don't need to use an if statement here
}
If you have a data_struct_1 or data_struct_2 and want to pass a reference to the object, rather than a copy, you could use pointers in the std::variant instead (although it'll get a bit confusing with std::get_if because you'll end up with a pointer to a pointer):
typedef std::variant<data_struct_1*, data_struct_2*> data_struct_1_or_2_ptr;
A simple C solution would be a union with a bool tag:
typedef struct {
struct head;
bool type_flag;
union{
struct data1 d1;
struct data2 d2
};
} data_struct;
std::variant is an overkill for this case IMO. Inheritance and runtime polymorphism is a waste of runtime and memory.
Regards,
FM.

Union vs inheritance in structures

Assume I have some structures, which basically have a 'general' field, and some unique data, like:
struct A
{
char type;
int data;
};
struct B
{
char type;
int data[2];
};
And etc (I have a lot of them). So I can just make a base structure with same fields, and inherit others. I though that I can do the same thing using union, e.g.:
union AnyClass
{
struct A _a;
struct B _b;
...
};
I am receiving some data (which exactly fits the biggest member in union), so would prefer to use following syntax:
// to read it from buffer (I am receiving data from another PC, which stores data the same way (in the same union) as I do
char buf[sizeof(AnyClass)];
char type = buf[0]; // detect type
AnyClass inst;
memcpy(&inst, buf, sizeof(inst));
switch(type)
{
... // handle data according to its type
}
// if I want to create a new object, and send it, I can use
AnyClass myObj;
new (&myObj._b) B();
... // do whatever I want
NOTE: I am aware that I have to align data somehow, so both machines (received/sender) should interpretate buf correctly.
Can it run faster than same problem solution using BaseStructure and inherited others (so, I have to cast them right away), or it will be compiled to nearly the same code?
Is it OK to use, or it is just a poor design?
If there is another solution, can you explain it shortly?
The performance difference between mentioned approaches will be minor. It is a good chance that you will not notice it at all.
I would shape your classes like that:
class AnyClass
{
char type;
union
{
struct
{
int data1;
};
struct
{
int data2[2];
};
};
;
Note using anonymous structs and unions.
Why do you need the character buffer at all? Always allocate the typed structure and better define it without ctors and dectors. I do not like this line:
char type = buf[0]; // detect type
Here you directly assume the physical offset. The less assumptions about the layout of the structures you make, the better the result will be.

Can I static_assert without providing a real template parameter?

template<typename T>
class MyClass
{
......
private:
union u_
{
struct m_
{
int i1;
int i2;
int i3;
} m;
char data[SIZE]; // convenience buffer for serialization/deserialization;
} u;
T container;
......
};
To be able to serialize / deserialize an object of MyClass, I use a union to combine my data fields and use the data buffer to do it wholesale. I want to make sure that data is big enough for the collection of data members in case someone expand them in the future, so I added this static assert.
static_assert(sizeof(MyClass<int>::u_::data) >= sizeof(MyClass<int>::u_::m_));
There are two problems with this approach. First, the compiler complains that the union is not public. Secondly this should hold true for any container type T, so I don't want to be specific, but giving int as a dummy type won't work, but I don't want to introduce another type just for the sake of static assert, is there a way to use a dummy type here?
Is there a more elegant solution?
EDIT: James, thanks for bringing up portability issues. Endianness and alignment are legit concerns, but in my case, serialization/deserialization happens locally, so it's OK.
Is there a more elegant solution?
Why not just reinterpret the struct as an array of char?
struct m_
{
int i1;
int i2;
int i3;
};
// ...
m_ m;
char* data = static_cast<char*>(static_cast<void*>(&m));
Any object can safely be reinterpreted as an array of char. Of course, you still have to worry about alignment, padding, the sizes of your data types, and potential endianness and other representation issues, but presumably you know that since you're writing the serialization implementation.
char data[SIZE];
Instead of this, you can do this:
char data[sizeof(m_)];
It'll always satisfy the condition in this static_assert:
static_assert(sizeof(MyClass<int>::u_::data) >= sizeof(MyClass<int>::u_::m_));
Since it'll always satisfy, no matter what, you would not even need to write the static_assert!
To solve the private issue you can consider putting static_assert somewhere inside the class, like a constructor or a static method for example.

Aligning Member Variables By Template Type

I want to align my member variables based on a class template type but I'm not sure if it is actually possible.
The following is a (very) simple example of what I'd like to do
template<int Align>
class MyClass
{
private:
struct MyStruct
{
// Some stuff
} __declspec(align(Align));
__declspec(align(Align)) int myAlignedVariable;
};
So what I'd like is for Align to be a per-instance variable, and only through that is the align value of the class contents decided.
Unfortunately I always get the following error
error C2975: 'test::MyClass' : invalid template argument for 'Align', expected compile-time constant expression
So, is this actually possible or can the alignment only be possible using a fixed compile time constant? If not, can anyone think of a way around this?
Thanks :)
Custom alignment isn't in the standard, so how the compilers deal with it is up to them - looks like VC++ doesn't like combining templates with __declspec.
I suggest a work-around using specialisation, something like this:
template<int A> struct aligned;
template<> struct aligned<1> { } __declspec(align(1));
template<> struct aligned<2> { } __declspec(align(2));
template<> struct aligned<4> { } __declspec(align(4));
template<> struct aligned<8> { } __declspec(align(8));
template<> struct aligned<16> { } __declspec(align(16));
template<> struct aligned<32> { } __declspec(align(32));
and then derive from that in your code:
template<int Align>
class MyClass
{
private:
struct MyStruct : aligned<Align> {
// stuff
};
};
This unfortunately breaks the POD-ness of MyStruct. It also doesn't work with built-in/existing types, so you'll have to use a wrapper for those.
aligned_t<int, 4> myAlignedVariable;
Boost has solved this problem already. They use the technique in boost::optional (link to header), which has to hold enough space for an aligned, arbitrary type but can't (won't) actually instantiate that object on construction.
Their solution was to allocate a simple pool of bytes (char array) and use in-place new to construct objects at the desired location. The address given to in-place new can be of any arbitrary alignment.
That being said, you're saying that you're giving a very simple example in your question. What is the actual problem that you're trying to solve by implementing a class where every member has a user-specified alignment that doesn't vary per member but can vary per class instance?