I've been messing with metaprogramming and variadic templates in C++, and I came up with this very primitive implementation of a tuple:
constexpr bool GreaterThanZero(int N)
{
return N > 0;
}
template <int, typename...>
struct Helper;
template <int N, typename Head, typename... Tail>
struct Helper<N, Head, Tail...>
{
typedef typename Helper<N-1, Tail...>::type type;
};
template <typename Head, typename... Tail>
struct Helper<0, Head, Tail...>
{
typedef Head& type;
};
template <int, typename...>
class TupleImpl;
template <>
class TupleImpl<-1>
{
};
template <typename Head>
class TupleImpl<0, Head>
{
protected:
Head head;
public:
template <int Depth>
Head& get()
{
static_assert(Depth == 0, "Requested member deeper than Tuple");
return head;
}
template <int Depth>
const Head& get() const
{
static_assert(Depth == 0, "Requested member deeper than Tuple");
return head;
}
};
template <int N, typename Head, typename... Tail>
class TupleImpl<N, Head, Tail...>
{
protected:
Head head;
TupleImpl<N-1, Tail...> tail;
public:
template <int M>
typename std::enable_if<M == 0, Head&>::type get()
{
return head;
}
template <int M>
typename std::enable_if<GreaterThanZero(M), typename Helper<M, Head, Tail...>::type>::type get()
{
return tail.get<M-1>();
}
template <int M>
typename std::enable_if<M == 0, const Head&>::type get() const
{
return head;
}
template <int M>
typename std::enable_if<GreaterThanZero(M), typename Helper<M, Head, Tail...>::type>::type get() const
{
return tail.get<M-1>();
}
};
template <typename... Elements>
class Tuple : public TupleImpl<sizeof...(Elements)-1, Elements...>
{
public:
static constexpr std::size_t size()
{
return sizeof...(Elements);
}
};
int main()
{
using namespace std;
Tuple<int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int> test;
Tuple<> test2;
test.get<0>() = 1;
test.get<1>() = 2;
cout << test.size() << endl;
cout << test.get<0>() << endl;
cout << test.get<1>() << endl;
}
Being template metaprogramming, of course it looks terrible. Are there any ways I can clean it up? I've been picking up the nitty-gritty details of how templates work by messing around with stuff like this, but I'm sure I'm missing something that would simplify this.
GreaterThanZero
might as well just use:return N > 0;
as its body. \$\endgroup\$