You need add a template before ::entry
template<int Index> // ...................VVVVVVVVV
auto entry() -> decltype(Tuple<Types...>::template entry<Index-1>())&
{ // .......................VVVVVVVVV
return Tuple<Types...>::template entry<Index-1>();
}
or the < after ::entry is parsed as a relational operator.
But you have another problem: the specialization of entry():
template<>
Type& entry<0>()
{
return value;
}
Unfortunately you can't specialize the a method without specializing the containing class.
If you can compile C++17, you can avoid method specialization and use if constexpr
template <int Index>
auto & entry()
{
if constexpr ( Index == 0 )
return value;
else
return Tuple<Types...>::template entry<Index-1>();
}
Pre C++17 In C++14... I suppose you can solve using tag dispatching
template <int>
Type & entry_helper (std::true_type)
{ return value; }
template <int Index>
auto & entry_helper (std::false_type)
{ return Tuple<Types...>::template entry<Index-1>(); }
template <int Index>
auto & entry()
{ return entry_helper<Index>(std::integral_constant<bool, Index==0>{}); }
In C++11 you need also the trailing return type in for entry() and for the second entry_helper()
As pointed by Patrick Roberts (thanks!) the solution, adding trailing return type, works for C++11 with g++ but not for clang++, for a problem in detecting the return type in a context of recursion.
For C++11 I propose a completely different solution that avoid the entry()/entry_helper() recursion but add another level of indirection at class level (add a recursive base class struct Tpl). Add also perfect forwarding, unsigned indexes and const-versions for entry() and entry_helper().
#include <utility>
#include <iostream>
#include <type_traits>
template <std::size_t, typename...>
struct Tpl
{ void entry_helper () {} };
template <std::size_t I, typename T, typename ... Ts>
struct Tpl<I, T, Ts...> : public Tpl<I+1u, Ts...>
{
using Tpl<I+1, Ts...>::entry_helper;
Tpl (T && t, Ts && ... ts)
: Tpl<I+1u, Ts...>{std::forward<Ts>(ts)...}, value{std::forward<T>(t)}
{ }
T value;
T & entry_helper (std::integral_constant<std::size_t, I>)
{ return value; }
T const & entry_helper (std::integral_constant<std::size_t, I>) const
{ return value; }
};
template <typename ... Ts>
struct Tuple : public Tpl<0, Ts...>
{
using Tpl<0, Ts...>::entry_helper;
Tuple (Ts && ... ts) : Tpl<0u, Ts...>{std::forward<Ts>(ts)...}
{ }
template <std::size_t I>
auto entry ()
-> decltype(entry_helper(std::integral_constant<std::size_t, I>{})) &
{ return entry_helper(std::integral_constant<std::size_t, I>{}); }
template <std::size_t I>
auto entry () const
-> decltype(entry_helper(std::integral_constant<std::size_t, I>{})) const &
{ return entry_helper(std::integral_constant<std::size_t, I>{}); }
};
int main()
{
Tuple<int, int, std::string, double> t(1, 2, "Hello World", 3.4);
std::cout << t.entry<1>() << std::endl; // Prints 2
std::cout << t.entry<2>() << std::endl; // Prints "Hello World"
}