I have written the following basic Tuple template:
template
class Tuple;
template
struct TupleIndex
I was having a hard time wrapping my head around the solutions I was finding, so I fashioned one of my own. All of the members in my tuple derive from the same class, so I adapted my previous solution by adding a base type parameter to my tuple class and using pointers-to-members:
template
class Tuple;
template
struct TupleIndexer;
template
struct TupleOffsets;
template
struct TupleOffsets {
TupleOffsets() { Init ::*>(offsets); }
Base Tuple ::* const& operator[] (uintptr_t i) const { return offsets[i]; }
template
static void Init(PtrType* offsets);
private:
Base Tuple ::* offsets[sizeof...(Tail) + 1];
};
template
template
void TupleOffsets ::Init(PtrType* offsets) {
*offsets = PtrType(&Tuple ::element);
TupleOffsets ::Init(++offsets);
}
template
struct TupleOffsets {
TupleOffsets() {}
template
static void Init(PtrType* offsets) {}
};
template
class Tuple : public Tuple {
private:
Head element;
public:
Base* Get(uintptr_t i) {
return &(this->*offsets[i]);
}
template
typename TupleIndexer ::Type& Get() {
return TupleIndexer ::Get(*this);
}
uintptr_t GetCount() const {
return sizeof...(Tail) + 1;
}
private:
static const TupleOffsets offsets;
friend struct TupleOffsets ;
friend struct TupleIndexer ;
};
template
const TupleOffsets Tuple ::offsets;
template
class Tuple {
public:
uintptr_t GetCount() const {
return 0;
}
};
template
struct TupleIndexer {
typedef Head& Type;
static Type Get(Tuple & tuple) {
return tuple.element;
}
};
template
struct TupleIndexer {
typedef typename TupleIndexer ::Type Type;
static Type Get(Tuple & tuple) {
return TupleIndexer ::Get(*(Tuple *) &tuple);
}
};
The following now works nicely, which is what I was ultimately shooting for:
struct Base {
virtual void print() = 0;
};
struct Derived1 : public Base {
virtual void print() { cout << "I'm the first derived class!" << endl; }
};
struct Derived2 : public Base {
virtual void print() { cout << "Woohoo! I'm the second derived class!" << endl; }
};
...
Tuple var;
var.Get(0)->print();
var.Get(1)->print();