I'm trying implement a tuple-like class. Everything works well. This is my code:
Tuple.hpp
#pragma once
template<typename Head, typename... Tail>
class Tuple : private Tuple<Tail...>
{
using Base = Tuple<Tail...>;
public:
Tuple(Head head, Tail... tail) : Base{ tail... }, m_head{ head }{};
Head& GetHead()
{
return m_head;
}
Base* base()
{
return static_cast<Base*>(this);
}
const Base* base() const
{
return static_cast<const Base*>(this);
}
private:
Head m_head;
};
template<typename Head>
class Tuple<Head>
{
public:
Tuple(Head head) : m_head{ head } {};
Head& GetHead()
{
return m_head;
}
private:
Head m_head;
};
template<int N, typename... Tail>
struct select;
template<int N, typename Head, typename... Tail>
struct select<N, Head, Tail...> : select<N - 1, Tail...>
{};
template<typename Head, typename... Tail>
struct select<0, Head, Tail...>
{
using type = Head;
};
template<int N, typename... Tail>
using Select = typename select<N, Tail...>::type;
template<int N, typename R>
struct TgetNth
{
template<typename T>
static R& get(T& t)
{
return TgetNth<N - 1, R>::get(*t.base());
}
};
template<typename R>
struct TgetNth<0, R>
{
template<typename T>
static R& get(T& t)
{
return t.GetHead();
}
};
template<int N, typename... Tail>
Select<N, Tail...> get(Tuple<Tail...>& t)
{
return TgetNth<N, Select<N, Tail...>>::get(t);
}
main.cpp
#include <iostream>
#include "Tuple.hpp"
int main()
{
Tuple<double, int, std::string, double> tup{ 1.1, 10, "Hello world", 2.2 };
std::cout << get<0>(tup) << std::endl;
std::cout << get<1>(tup) << std::endl;
std::cout << get<2>(tup) << std::endl;
std::cout << get<3>(tup) << std::endl;
return 0;
}
As you can see, struct TgetNth
uses public methods Head& Tuple::GetHead()
and Base* Tuple::base()
. My idea to make these methods private and declare struct TgetNth
as a friend of Tuple
. I tried to make it like this:
friend struct TgetNth<0, Select<0, Tail...>>;
But I get an error from the compiler:
error C2248: 'Tuple<double,int,std::string,double>::m_head': cannot access private member declared in class 'Tuple<double,int,std::string,double>'
I'll be honest. I don't have any ideas how to do it. The snag is the int N
parameter of the template.
You can make the entire TgetNth
template a friend by declaring the following in Tuple
:
template<int, typename>
// or template <int N, typename R>, but names are unnecessary
friend struct TgetNth;