How to write an inheritable template class with operators - c++

I am hoping that it is possible to write a template class that will be inherited for several type-specific sub-classes. I want the inherited methods and operators to return the type of the sub-class rather than the parent template type. This is in hopes of saving lots of development and maintenance effort if I only have to modify one base class.
Here is an example of what I have already:
template<typename T> struct TMonoPixel
{
T value;
TMonoPixel(T v) { value = v; }
// the template has some pure virtual functions here...
TMonoPixel operator+ (const TMonoPixel& other)
{ return TMonoPixel(value + other.value); }
}
struct Mono8Pixel : TMonoPixel<uint8_t>
{
using TMonoPixel::TMonoPixel; // I want to inherit the constructor
// each pixel type implements the virtual functions in the template
}
As you can see the Mono8Pixel struct inherits the + operator which accepts TMonoPixel, but using this operator returns TMonoPixel<uint8_t> rather than Mono8Pixel because it is defined in the base class.
I am planning to use these structs for iterating over pixels in an image:
Image* img; // img has an unsigned char* pointer to its pixel data
for (int row=0; row<img->height; row++) {
for (int col=0; col<img->width; col++) {
int i = (row*img->width + col);
Mono8Pixel* pixel = reinterpret_cast<Mono8Pixel*>(img->dataPtr + sizeof(unsigned char)*i);
// modify the pixel ...
}
}
Is there any way to change just the template class to ensure that Mono8Pixel(2) + Mono8Pixel(2) is returning a Mono8Pixel?
Note that whatever the solution is, these structs must maintain standard layout because of how I wish to use them.

What you want can be done using the curiously recurring template pattern (CRTP). The basic idea is this:
template<class Pixel> struct TMonoPixel {
...
// not virtual
std::string GetSomeProperty() const {
return static_cast<const Pixel&>(*this).GetSomeProperty();
}
Pixel operator+(const TMonoPixel& other) const {
return Pixel(value + other.value);
}
};
struct Mono8Pixel : TMonoPixel<Mono8Pixel> {
using TMonoPixel::TMonoPixel;
std::string GetSomeProperty() const {
return "My name is Mono8Pixel";
}
};
Thanks to implicit derived-to-base conversion now you can use it like this:
template<class T>
void foo(const TMonoPixel<T>& number) {
std::cout << number.GetSomeProperty();
}
Mono8Pixel i;
foo(i);
Note that inside TMonoPixel, Pixel is an incomplete type, so you have some limitations on how it can be used. For example, you can't do this:
template<class Pixel> struct TMonoPixel {
Pixel::Type operator+(const TMonoPixel& other);
};
struct Mono8Pixel : TMonoPixel<Mono8Pixel> {
using Type = std::uint8_t;
};
Type traits is a useful technique to overcome such limitations:
struct Mono8Pixel;
template<class Pixel> struct ValueType;
template<> struct ValueType<Mono8Pixel> {
using Type = std::uint8_t;
};
template<class Pixel> struct TMonoPixel {
using Type = typename ValueType<Pixel>::Type;
Type value;
TMonoPixel(Type value) : value(value)
{}
Pixel operator+(const TMonoPixel& other) const {
return Pixel(value + other.value);
}
};
struct Mono8Pixel : TMonoPixel<Mono8Pixel> {
using TMonoPixel::TMonoPixel;
};
The type of Mono8Pixel(2) + Mono8Pixel(2) is Mono8Pixel.
So I guess I'm asking whether these CRTP-based structs have standard layout after all of these changes to the type of value.
They do:
static_assert(std::is_standard_layout_v<Mono8Pixel>);
Complete example: https://godbolt.org/z/8z0CKX

Related

Template a member variable

Consider the following two classes:
class LunchBox
{
public:
std::vector<Apple> m_apples;
};
and
class ClassRoom
{
public:
std::vector<Student> m_students;
};
The classes are alike in that they both contain a member variable vector of objects; however, they are unalike in that the vector's objects are different and the member variables have different names.
I would like to write a template that takes either LunchBox or ClassRoom as a template argument (or some other parameter) and an existing object of the same type (similar to a std::shared_ptr). The template would return an object that adds a getNthElement(int i); member function to improve accessing the methods. Usage would be like:
// lunchBox is a previously initialized LunchBox
// object with apples already pushed into m_apples
auto lunchBoxWithAccessor = MyTemplate<LunchBox>(lunchBox);
auto apple3 = lunchBoxWithAccessor.getNthElement(3);
I would like to do this without writing template specializations for each class (which likely would require specifying the member variable to operate on in some way). Preferably, I do not want to modify the LunchBox or ClassRoom classes. Is writing such a template possible?
You can minimize the amount of code that has to be written for each class -- it doesn't have to be a template specialization and it doesn't have to be an entire class.
class LunchBox
{
public:
std::vector<Apple> m_apples;
};
class ClassRoom
{
public:
std::vector<Student> m_students;
};
// you need one function per type, to provide the member name
auto& get_associated_vector( Student& s ) { return s.m_apples; }
auto& get_associated_vector( ClassRoom& r ) { return r.m_students; }
// and then the decorator is generic
template<typename T>
class accessor_decorator
{
T& peer;
public:
auto& getNthElement( int i ) { return get_associated_vector(peer).at(i); }
auto& takeRandomElement( int i ) { ... }
// many more ways to manipulate the associated vector
auto operator->() { return &peer; }
};
LunchBox lunchBox{};
accessor_decorator<LunchBox> lunchBoxWithAccessor{lunchBox};
auto apple3 = lunchBoxWithAccessor.getNthElement(3);
The simple helper function overload should ideally be in the same namespace as the type, to make argument-dependent lookup work (aka Koenig lookup).
It's also possible to specify the member at the point of construction, if you prefer to do that:
template<typename T, typename TMemberCollection>
struct accessor_decorator
{
// public to make aggregate initialization work
// can be private if constructor is written
T& peer;
TMemberCollection const member;
public:
auto& getNthElement( int i ) { return (peer.*member).at(i); }
auto& takeRandomElement( int i ) { ... }
// many more ways to manipulate the associated vector
auto operator->() { return &peer; }
};
template<typename T, typename TMemberCollection>
auto make_accessor_decorator(T& object, TMemberCollection T::*member)
-> accessor_decorator<T, decltype(member)>
{
return { object, member };
}
LunchBox lunchBox{};
auto lunchBoxWithAccessor = make_accessor_decorator(lunchBox, &LunchBox::m_apples);
auto apple3 = lunchBoxWithAccessor.getNthElement(3);
A simple way to do this is define a trait struct that has specializations with just the information that makes each case different. Then you have a template class that uses this traits type:
// Declare traits type. There is no definition though. Only specializations.
template <typename>
struct AccessorTraits;
// Specialize traits type for LunchBox.
template <>
struct AccessorTraits<LunchBox>
{
typedef Apple &reference_type;
static reference_type getNthElement(LunchBox &box, std::size_t i)
{
return box.m_apples[i];
}
};
// Specialize traits type for ClassRoom.
template <>
struct AccessorTraits<ClassRoom>
{
typedef Student &reference_type;
static reference_type getNthElement(ClassRoom &box, std::size_t i)
{
return box.m_students[i];
}
};
// Template accessor; uses traits for types and implementation.
template <typename T>
class Accessor
{
public:
Accessor(T &pv) : v(pv) { }
typename AccessorTraits<T>::reference_type getNthElement(std::size_t i) const
{
return AccessorTraits<T>::getNthElement(v, i);
}
// Consider instead:
typename AccessorTraits<T>::reference_type operator[](std::size_t i) const
{
return AccessorTraits<T>::getNthElement(v, i);
}
private:
T &v;
};
A few notes:
In this case, the implementation would technically be shorter without a traits type; with only specializations of Accessor for each type. However, the traits pattern is a good thing to learn as you now have a way to statically reflect on LunchBox and ClassRoom in other contexts. Decoupling these pieces can be useful.
It would be more idiomatic C++ to use operator[] instead of getNthElement for Accessor. Then you can directly index the accessor objects.
AccessorTraits really isn't a good name for the traits type, but I'm having trouble coming up with anything better. It's not the traits of the accessors, but the traits of the other two relevant classes -- but what concept even relates those two classes? (Perhaps SchoolRelatedContainerTraits? Seems a bit wordy...)
You said:
I would like to do this without writing template specializations for each class
I am not sure why that is a constraint. What is not clear is what else are you not allowed to use.
If you are allowed to use couple of function overloads, you can get what you want.
std::vector<Apple> const& getObjects(LunchBox const& l)
{
return l.m_apples;
}
std::vector<Student> const& getObjects(ClassRoom const& c)
{
return c.m_students;
}
You can write generic code that works with both LaunchBox and ClassRoom without writing any other specializations. However, writing function overloads is a form of specialization.
Another option will be to update LaunchBox and ClassRoom with
class LunchBox
{
public:
std::vector<Apple> m_apples;
using ContainedType = Apple;
};
class ClassRoom
{
public:
std::vector<Student> m_students;
using ContainedType = Apple;
};
and then, take advantage of the fact that
LaunchBox b;
std::vector<Apple>* ptr = reinterpret_cast<std::vector<Apple>*>(&b);
is a legal construct. Then, the following class will work fine.
template <typename Container>
struct GetElementFunctor
{
using ContainedType = typename Container::ContainedType;
GetElementFunctor(Container const& c) : c_(c) {}
ContainedType const& getNthElement(std::size_t n) const
{
return reinterpret_cast<std::vector<ContainedType> const*>(&c_)->operator[](n);
}
Container const& c_;
};
and you can use it as:
LunchBox b;
b.m_apples.push_back({});
auto f = GetElementFunctor<LunchBox>(b);
auto item = f.getNthElement(0);
I did a test case sample using a few basic classes:
class Apple {
public:
std::string color_;
};
class Student {
public:
std::string name_;
};
class LunchBox {
public:
std::vector<Apple> container_;
};
class ClassRoom {
public:
std::vector<Student> container_;
};
However for the template function that I wrote I did however have to change the name of the containers in each class to match for this to work as this is my template function:
template<class T>
auto accessor(T obj, unsigned idx) {
return obj.container_[idx];
}
And this is what my main looks like:
int main() {
LunchBox lunchBox;
Apple green, red, yellow;
green.color_ = std::string( "Green" );
red.color_ = std::string( "Red" );
yellow.color_ = std::string( "Yellow" );
lunchBox.container_.push_back(green);
lunchBox.container_.push_back(red);
lunchBox.container_.push_back(yellow);
ClassRoom classRoom;
Student s1, s2, s3;
s1.name_ = std::string("John");
s2.name_ = std::string("Sara");
s3.name_ = std::string("Mike");
classRoom.container_.push_back(s1);
classRoom.container_.push_back(s2);
classRoom.container_.push_back(s3);
for (unsigned u = 0; u < 3; u++) {
auto somethingUsefull = accessor(lunchBox, u);
std::cout << somethingUsefull.color_ << std::endl;
auto somethingElseUsefull = accessor(classRoom, u);
std::cout << somethingElseUsefull.name_ << std::endl;
}
return 0;
}
I'm not sure if there is a work around to have a different variable name from each different class this function can use; but if there is I haven't figured it out as of yet. I can continue to work on this to see if I can improve it; but this is what I have come up with so far.

C++ BigIntegers and the Curiously Recurring Template Pattern Issue

I'm implementing a Big Integer library where the user can choose between fixed precision or arbitrary precision integers. Since great part of the code is shared between the two entities I've decided to use the CRTP to implement the Integer operations just once.
In short there is a base class named UInteger and two derived classes named UIntegerFP (fixed precision) and UIntegerAP (arbitrary precision).
Follows a skeleton of the implementation:
template <typename Derived>
class UInteger
{
public:
UInteger<Derived> &operator +=(const UInteger<Derived> &rhs);
...
};
template <int blocks>
class UIntegerFP : public UInteger<UIntegerFP>
{
public:
int get_size() { return m_len; }
void set_size(int size) { m_len = len; }
private:
std::array<uint32_t, blocks> m_data;
int m_len;
};
class UIntegerAP : public UInteger<UIntegerAP>
{
public:
int get_size() { return m_data.size(); }
void set_size(int size) { m_data.resize(len); }
private:
std::vector<uint32_t> m_data;
};
The base class uses a couple of methods exposed by the derived classes to interact with implementation dependent aspects (ie like get_size/set_size).
My problem:
I want to implement a global binary operator+() that returns the result of the operation by value in the UInteger "generic" header file in this way:
template <typename Derived>
UInteger<Derived> operator+(const UInteger<Derived> &x0,
const UInteger<Derived> &x1)
{
Derived res = static_cast<Derived>(x0);
x0 += x1;
return x0;
}
The problem is that, since the result is returned by value, it is casted to the base class type loosing the implementation details (e.g. the m_data vector destructor is called).
Obviously I do not get this problem if I define the function to return a Derived type by value:
template <typename Derived>
Derived operator+(const UInteger<Derived> &x0,
const UInteger<Derived> &x1)
{
Derived res = static_cast<Derived>(x0);
x0 += x1;
return x0;
}
But I don't like too much this approach, epecially from a design point of view.
Is there a better solution to such problem? Maybe I should define such operators directly just for the derived classes?
Is there someone thinking that the CRTP is not very appropriate here and maybe is better to directly implement just one UInteger class in this way:
template <bool dynamic = true>
class UInteger
{
...
private:
std::array<uint32_t> m_data;
int m_len; <- how much of m_data array is actually in use
}
and if the bool "dynamic" value is false I never reallocate the vector obtaining something similar to the UIntegerFP template class. Maybe (if the compiler is smart enough) , since the boolean is a const template parameter, I also abtain something like conditional code compilation?!
Suggestions of any type are very welcome,
Thanks,
Davide
I don't quite understand why you want to use CRTP here in this way.
CRTP is the natural way to implement the actual details of the = and += operations, when only the memory management is done via the derived methods. Such design clearly separates the two task of arithmetic and memory management to different classes. The + (binary) operator is then best implemented as stand-alone function template.
Something like this:
namespace biginteger_details {
template<typename UInteger>
class UIntegerBase // CRTP base, implementing the arithmetics
{
using uint32_t = std::uint32_t;
using size_t = std::size_t;
// access to data: all functionality is implemented through these methods
uint32_t&block(size_t i) { return static_cast< UInteger*>(this)->m_data[i]; }
uint32_t block(size_t i) const { return static_cast<const UInteger*>(this)->m_data[i]; }
size_t size() const { return static_cast<const UInteger*>(this)->size(); }
void resize(size_t n) { static_cast<UInteger*>(this)->resize(n); }
public:
// assignment operator: allow assignment from any UInteger type
template<typename UI>
UInteger&operator=(UIntegerBase<UI> const&other)
{
resize(other.size());
for(size_t i=0; i!=size(); ++i)
block(i) = other.block(i);
return static_cast<UInteger&>(*this);
}
// add and assign: allow adding any UInteger type
template<typename UI>
UInteger&operator+=(UIntegerBase<UI> const&other)
{
// your code here using block(), size(), and resize()
return static_cast<UInteger&>(*this);
}
};
template<std::size_t nblock=8>
struct UIntegerFP
: UIntegerBase<UIntegerFP<nblock>>
{
static constexpr std::size_t max_blocks=nblock;
// 1 data
std::array<std::uint32_t,nblock> m_data;
std::size_t m_size=0;
// 2 interface to base
std::size_t size() const { return m_size; }
void resize(std::size_t n)
{
if(n>nblock) throw std::out_of_range("exceeding capacity");
m_size = n;
}
// 3 constructors
// copy constructor from any UInteger type
template<typename UI>
UIntegerFP(UIntegerBase<UI> const&other)
{ this->operator=(other); }
};
struct UIntegerAP
: UIntegerBase<UIntegerAP>
{
static constexpr std::size_t max_blocks=~(std::size_t(0));
// 1 data,
std::vector<std::uint32_t> m_data;
// 2 interface to base
std::size_t size() const { return m_data.size(); }
void resize(std::size_t n)
{ m_data.resize(n); }
// 3 constructors
// copy constructor from any UInteger type
template<typename UI>
UIntegerAP(UIntegerBase<UI> const&other)
{ this->operator=(other); }
};
// functions best take UIntegerBase<UI> arguments, for example:
// operator + as stand alone function template
template<typename Ulhs, typename Urhs>
inline std::conditional_t<(Ulhs::max_blocks > Urhs::max_blocks), Ulhs, Urhs>
operator+(UIntegerBase<Ulhs> const&lhs, UIntegerBase<Urhs> const&rhs)
{
std::conditional_t<(Ulhs::max_blocks > Urhs::max_blocks), Ulhs, Urhs>
result=lhs;
return result+=rhs;
}
} // namespace biginteger_details;
using biginteger_details::UIntegerFP;
using biginteger_details::UIntegerAP;
// note: biginteger_details::operator+ will be found by ADL (argument dependent look-up)
In your operator+ implementation, in practice, you are setting the function return type as:
UIntegerAP if one of the template types is an UIntegerAP.
Ulhs, otherwise (here I suppose you intend UIntegerFP).
Is that right?
Now... what if the UIntegerAP is a template as well? For example defined like this:
template <typename block_type>
class UIntegerAP
{
....
private:
std::vector<block_type> m_data;
}
I cannot use UIntegerAP type in the operator+ declaration anymore.

C++ auto deduction of return type

I want to write a function that return different types based on different input as below.
enum MyType
{
A,
B
};
template<MyType T> struct MyStruct
{
};
static auto createMyStruct(MyType t)
{
if(t==A)
return MyStruct<A>();
else
return MyStruct<B>();
}
It didn't work out because there are two return types for one auto. Is there any other way to do this?
There is absolutely no way of having a (single) function that returns different types based on a runtime decision. The return type has to be known at compile time. However, you can use a template function, like this (thanks to #dyp for making me simplify the code):
#include <iostream>
#include <typeinfo>
enum MyType
{
A,
B
};
template<MyType>
struct MyStruct {};
template<MyType type>
MyStruct<type> createMyStruct()
{
return {};
}
int main()
{
auto structA = createMyStruct<A>();
auto structB = createMyStruct<B>();
std::cout << typeid(structA).name() << std::endl;
std::cout << typeid(structB).name() << std::endl;
}
I am assuming you want to write code like this:
void foo (MyType t) {
auto x = createMyStruct(t);
//... do something with x
}
You are attempting to derive the right type for x at runtime. However, the return type of a function must be known at compile time, and the type resolution for auto is also determined at compile time.
You could instead restructure your code to be like this:
template<MyType T> struct MyStruct
{
//...
static void foo () {
MyStruct x;
//... do something with x
}
};
The idea is to write a single foo() function whose only difference is the type of thing it is manipulating. This function is encapsulated within the type itself. You can now make a runtime decision if you have a mapping between MyType and MyStruct<MyType>::foo.
typedef std::map<MyType, void(*)()> MyMap;
template <MyType...> struct PopulateMyMap;
template <MyType T> struct PopulateMyMap<T> {
void operator () (MyMap &m) {
m[T] = MyStruct<T>::foo;
}
};
template <MyType T, MyType... Rest> struct PopulateMyMap<T, Rest...> {
void operator () (MyMap &m) {
m[T] = MyStruct<T>::foo;
PopulateMyMap<Rest...>()(m);
}
};
template<MyType... Types> void populateMyMap (MyMap &m) {
PopulateMyMap<Types...>()(m);
}
//...
populateMyMap<A, B>(myMapInstance);
Then, to make a runtime decision:
void foo (MyType t) {
myMapInstance.at(t)();
}
I think you should learn abstract factory design pattern.
For use objects of type MyStruct<A> or MyStruct<B> you need common interface.
Common interface provided in abstract base class.
struct MyStruct
{
virtual ~MyStruct() {}
virtual void StructMethod() = 0;
};
struct MyStructA: public MyStruct
{
void StructMethod() override {}
};
struct MyStructB: public MyStruct
{
void StructMethod() override {}
};
std::unique_ptr<MyStruct> createMyStruct(MyType t)
{
if (t==A)
return std::make_unique<MyStructA>();
else
return std::make_unique<MyStructB>();
}

C++ Push Multiple Types onto Vector

Note: I know similar questions to this have been asked on SO before, but I did not find them helpful or very clear.
Second note: For the scope of this project/assignment, I'm trying to avoid third party libraries, such as Boost.
I am trying to see if there is a way I can have a single vector hold multiple types, in each of its indices. For example, say I have the following code sample:
vector<something magical to hold various types> vec;
int x = 3;
string hi = "Hello World";
MyStruct s = {3, "Hi", 4.01};
vec.push_back(x);
vec.push_back(hi);
vec.push_back(s);
I've heard vector<void*> could work, but then it gets tricky with memory allocation and then there is always the possibility that certain portions in nearby memory could be unintentionally overridden if a value inserted into a certain index is larger than expected.
In my actual application, I know what possible types may be inserted into a vector, but these types do not all derive from the same super class, and there is no guarantee that all of these types will be pushed onto the vector or in what order.
Is there a way that I can safely accomplish the objective I demonstrated in my code sample?
Thank you for your time.
The objects hold by the std::vector<T> need to be of a homogenous type. If you need to put objects of different type into one vector you need somehow erase their type and make them all look similar. You could use the moral equivalent of boost::any or boost::variant<...>. The idea of boost::any is to encapsulate a type hierarchy, storing a pointer to the base but pointing to a templatized derived. A very rough and incomplete outline looks something like this:
#include <algorithm>
#include <iostream>
class any
{
private:
struct base {
virtual ~base() {}
virtual base* clone() const = 0;
};
template <typename T>
struct data: base {
data(T const& value): value_(value) {}
base* clone() const { return new data<T>(*this); }
T value_;
};
base* ptr_;
public:
template <typename T> any(T const& value): ptr_(new data<T>(value)) {}
any(any const& other): ptr_(other.ptr_->clone()) {}
any& operator= (any const& other) {
any(other).swap(*this);
return *this;
}
~any() { delete this->ptr_; }
void swap(any& other) { std::swap(this->ptr_, other.ptr_); }
template <typename T>
T& get() {
return dynamic_cast<data<T>&>(*this->ptr_).value_;
}
};
int main()
{
any a0(17);
any a1(3.14);
try { a0.get<double>(); } catch (...) {}
a0 = a1;
std::cout << a0.get<double>() << "\n";
}
As suggested you can use various forms of unions, variants, etc. Depending on what you want to do with your stored objects, external polymorphism could do exactly what you want, if you can define all necessary operations in a base class interface.
Here's an example if all we want to do is print the objects to the console:
#include <iostream>
#include <string>
#include <vector>
#include <memory>
class any_type
{
public:
virtual ~any_type() {}
virtual void print() = 0;
};
template <class T>
class concrete_type : public any_type
{
public:
concrete_type(const T& value) : value_(value)
{}
virtual void print()
{
std::cout << value_ << '\n';
}
private:
T value_;
};
int main()
{
std::vector<std::unique_ptr<any_type>> v(2);
v[0].reset(new concrete_type<int>(99));
v[1].reset(new concrete_type<std::string>("Bottles of Beer"));
for(size_t x = 0; x < 2; ++x)
{
v[x]->print();
}
return 0;
}
In order to do that, you'll definitely need a wrapper class to somehow conceal the type information of your objects from the vector.
It's probably also good to have this class throw an exception when you try to get Type-A back when you have previously stored a Type-B into it.
Here is part of the Holder class from one of my projects. You can probably start from here.
Note: due to the use of unrestricted unions, this only works in C++11. More information about this can be found here: What are Unrestricted Unions proposed in C++11?
class Holder {
public:
enum Type {
BOOL,
INT,
STRING,
// Other types you want to store into vector.
};
template<typename T>
Holder (Type type, T val);
~Holder () {
// You want to properly destroy
// union members below that have non-trivial constructors
}
operator bool () const {
if (type_ != BOOL) {
throw SomeException();
}
return impl_.bool_;
}
// Do the same for other operators
// Or maybe use templates?
private:
union Impl {
bool bool_;
int int_;
string string_;
Impl() { new(&string_) string; }
} impl_;
Type type_;
// Other stuff.
};

Design Pattern, adding data to a class (3rd party) without modifying it

When I have to extend the behaviour of a class without modifying it, I often use the design pattern visitor. It adds member-like functions without modifying the core of the class it works with.
More or less in the same way, I need to extend a third party class, but mostly with data, not behaviour.
In such cases, I often use a std::map matching the a key MyClass* with a value MyClassExtender. MyClassExtender contains all the additionnal information.
While doing that, I happened to wonder if there are other ways of doing that, maybe more common or more 'best-practice". Should I call this additive class an Extender ?
Is there a name for such a pattern...
Nota Bene: I could have simply aggregated the MyClass* and MyClassExtender in a new class, but I need to access MyClassExtender given a MyClass* really often, so the st::map is really convinient.
Why don't you just subclass the class? Inheritance is the way to extend classes, whether with behavior or state. Unless you just want to associate instances of the class with other data, in which case it's not extending at all, and a std::map is the right answer.
So - create your MyClass object with in the struct with your extension objects:
struct MyClassEx {
MyClassExtension extension;
MyClass object;
};
To make it more robustness for different types - use templates from the example: http://ideone.com/mmfK83
The solution below is inspired by std::shared_ptr/std::make_shared:
template <typename Type>
struct LinkExtension;
template <typename Type>
struct TypeEx {
using Extension = typename LinkExtension<Type>::Type;
alignas(Type) uint8_t objectData[sizeof(Type)];
alignas(Extension) uint8_t extensionData[sizeof(Extension)];
Type* getObject() { return reinterpret_cast<Type*>(objectData); }
const Type* getObject() const { return reinterpret_cast<const Type*>(objectData); }
Extension* getExtension() { return reinterpret_cast<Extension*>(extensionData); }
const Extension* getExtension() const { return reinterpret_cast<const Extension*>(extensionData); }
template <class... Args>
TypeEx(Args&&... args)
{
new (objectData) Type(std::forward<Args>(args)...);
new (extensionData) Extension();
}
~TypeEx()
{
getObject()->~Type();
getExtension()->~Extension();
}
TypeEx(const TypeEx&) = delete;
TypeEx& operator = (const TypeEx&) = delete;
};
And some helper functions:
template <typename Type, class... Args>
Type* createObjectEx(Args&&... args)
{
TypeEx<Type>* retVal = new TypeEx<Type>(std::forward<Args>(args)...);
return retVal->getObject();
}
template <typename Type>
typename LinkExtension<Type>::Type& getObjectEx(Type* obj)
{
static_assert(std::is_standard_layout<TypeEx<Type>>::value, "Oops");
static_assert(offsetof(TypeEx<Type>, objectData) == 0, "Oops");
TypeEx<Type>* retVal = static_cast<TypeEx<Type>*>((void*)obj);
return *(retVal->getExtension());
}
template <typename Type>
const typename LinkExtension<Type>::Type& getObjectEx(const Type* obj)
{
static_assert(std::is_standard_layout<TypeEx<Type>>::value, "Oops");
static_assert(offsetof(TypeEx<Type>, objectData) == 0, "Oops");
const TypeEx<Type>* retVal = static_cast<const TypeEx<Type>*>((const void*)obj);
return *(retVal->getExtension());
}
template <typename Type>
void deleteObjectEx(const Type* obj)
{
const TypeEx<Type>* objectEx = static_cast<const TypeEx<Type>*>((const void*)obj);
delete objectEx;
}
And how to link extension to class:
class MyClass {
public:
virtual ~MyClass() = default;
};
struct MyClassExtension {
int a;
int b;
};
template <>
struct LinkExtension<MyClass> {
using Type = MyClassExtension;
};
And proof it works:
void printExtension(MyClass* object);
int main() {
MyClass* object = createObjectEx<MyClass>();
MyClassExtension& extension = getObjectEx(object);
extension.a = 1;
extension.b = 2;
printExtension(object);
deleteObjectEx(object);
TypeEx<MyClass> objectEx;
objectEx.getExtension()->a = 3;
objectEx.getExtension()->b = 4;
printExtension(objectEx.getObject());
}
void printExtension(MyClass* object)
{
MyClassExtension& extension = getObjectEx(object);
std::cout << extension.a << ' ' << extension.b << std::endl;
}
If your compiler does not support variadic templates, the solution is still possible, but requires more hand work to be complete.