I wrote the following basic Tuple template:
template <typename... T>
class Tuple;
template <uintptr_t N, typename... T>
struct TupleIndexer;
template <typename Head, typename... Tail>
class Tuple<Head, Tail...> : public Tuple<Tail...> {
private:
Head element;
public:
template <uintptr_t N>
typename TupleIndexer<N, Head, Tail...>::Type& Get() {
return TupleIndexer<N, Head, Tail...>::Get(*this);
}
uintptr_t GetCount() const {
return sizeof...(Tail) + 1;
}
private:
friend struct TupleIndexer<0, Head, Tail...>;
};
template <>
class Tuple<> {
public:
uintptr_t GetCount() const {
return 0;
}
};
template <typename Head, typename... Tail>
struct TupleIndexer<0, Head, Tail...> {
typedef Head& Type;
static Type Get(Tuple<Head, Tail...>& tuple) {
return tuple.element;
}
};
template <uintptr_t N, typename Head, typename... Tail>
struct TupleIndexer<N, Head, Tail...> {
typedef typename TupleIndexer<N - 1, Tail...>::Type Type;
static Type Get(Tuple<Head, Tail...>& tuple) {
return TupleIndexer<N - 1, Tail...>::Get(*(Tuple<Tail...>*) &tuple);
}
};
It works fine, and I can access the elements as an array using tuple.Get<Index>()- but I can only do this if I know the index at compile time. However, I need to access the elements in the tuple by index at runtime, and at compile time I will not know which index to access. Example:
int chosenIndex = getUserInput();
void* chosenElement = tuple.Get(chosenIndex);
cout << "The option you chose was: " << ((MyAbstractBaseClass*) chosenElement)->getInfo() << endl;
What is the best way to do this?
EDIT:
Hacking solution below:
Ok, I have an idea. I already figured out one way to do this before I even posted this question, but it was hacked and triggered warnings. Since the other solution is not right away, maybe you guys could help me improve my hacker approach. :-)
, , . (, , , .) , , . :
#include <cstddef>
template <typename... T>
class Tuple;
template <uintptr_t N, typename... T>
struct TupleIndexer;
template <typename... T>
struct TupleOffsets;
template <typename Head, typename... Tail>
struct TupleOffsets<Head, Tail...> {
TupleOffsets() { Init(offsets); }
static void Init(uintptr_t* offsets);
uintptr_t const& operator[] (uintptr_t i) const { return offsets[i]; }
private:
uintptr_t offsets[sizeof...(Tail) + 1];
};
template <typename Head, typename... Tail>
void TupleOffsets<Head, Tail...>::Init(uintptr_t* offsets) {
typedef Tuple<Head, Tail...> Type;
*offsets = offsetof(Type, element);
TupleOffsets<Tail...>::Init(++offsets);
}
template <>
struct TupleOffsets<> {
TupleOffsets() {}
static void Init(uintptr_t* offsets) {}
};
template <typename Head, typename... Tail>
class Tuple<Head, Tail...> : public Tuple<Tail...> {
private:
Head element;
public:
void* Get(uintptr_t i) {
return (uint8_t*) this + offsets[i];
}
template <uintptr_t N>
typename TupleIndexer<N, Head, Tail...>::Type& Get() {
return TupleIndexer<N, Head, Tail...>::Get(*this);
}
uintptr_t GetCount() const {
return sizeof...(Tail) + 1;
}
private:
static const TupleOffsets<Head, Tail...> offsets;
friend struct TupleOffsets<Head, Tail...>;
friend struct TupleIndexer<0, Head, Tail...>;
};
template <typename Head, typename... Tail>
const TupleOffsets<Head, Tail...> Tuple<Head, Tail...>::offsets;
template <>
class Tuple<> {
public:
uintptr_t GetCount() const {
return 0;
}
};
template <typename Head, typename... Tail>
struct TupleIndexer<0, Head, Tail...> {
typedef Head& Type;
static Type Get(Tuple<Head, Tail...>& tuple) {
return tuple.element;
}
};
template <uintptr_t N, typename Head, typename... Tail>
struct TupleIndexer<N, Head, Tail...> {
typedef typename TupleIndexer<N - 1, Tail...>::Type Type;
static Type Get(Tuple<Head, Tail...>& tuple) {
return TupleIndexer<N - 1, Tail...>::Get(*(Tuple<Tail...>*) &tuple);
}
};
. , offsetof , POD, , . - , ?