My container needs to store a little information about its elements. Normally, I store this separately from elements. However, I'd like to give users possibility to conserve memory by dedicating a field in element structure type for external use. E.g.:
struct MyStuff
{
int foo;
char bar;
mutable char dedicated_for_external_use; // Because of alignment, this field
// won't increase sizeof (MyStuff)
};
The idea here is that the field must not be accessed by anything but element's container. Since containers store a copy (much like std::vector
), it wouldn't be a problem if you added any given value x
to several containers.
How would you design an interface for this that, if possible, would meet the following requirements?
- Should be completely optional. I.e. it should be possible to automatically determine if given type provides such a field or not and then container would only use it if available.
- Ideally, wouldn't depend on type traits etc. as I need maximum compiler compatibility.
- Should be easy to use. I.e. if you can and want to enable this optimization for type
MyStuff
, you could do it with 3 lines of code, not 25. Internal complications, on the other hand, don't matter. - Should preferably exclude false positives completely. What I mean is: if you check for field
foo_bar
there is a small posibility that such field exists for a completely unrelated reason (and I think duck-typing is simply not for C++). A better way would be to check if type inherits marker classProvidesExternalUseField
from my library, as this can't be by accident.
EDIT
I know about Boost.Intrusive, but what I want is something different. If I go that way and create a hooks class with a single char
field, it cannot be used to conserve memory in many cases. If inherited type has an int
as first field, char
field will be padded to 4 bytes. I.e. you'd often need intricate knowledge of type internals to be able to "squeeze" such extern-use field in, but inheritance doesn't really provide it:
struct hooks { mutable char dedicated_for_external_use; };
struct MyStuff : hooks
{
int foo;
char bar;
};
Here, size of MyStuff
will be 12 bytes, not 8.
You can use partial template specialization for the case your data struct derives from the marker interface.
Let's say your marker interface class looks like this:
It is not virtual for a purpose: we wouldn't want to add a vtable pointer to a data class just for this.
Now let's implement a simple container class:
And here is how we change it to distinguish between the 2 cases:
Now you can define the structs like this:
And use the container class in the exact same way:
You can also further automate (templatize) getters and setters in the marker interface by using a poiter-to-member as a template parameter.