Reputation: 40058
I am looking for a projection function for std::tuple
. I.e., the function receives a list of integers as template parameters and returns a tuple that only has the values at these indexes.
For example, consider I have a tuple tuple<int,String,char,float> t
, then a call to project<1,3>(t)
would result in a tuple of type tuple<String,float>
.
Of course, the key seems to be recursive templates. However, I am unable to get it to work. I tried starting by declaring a struct to calculate the return type of a projection operation. Even that fails. Here is what I tried:
template<typename T, size_t... indexes>
class Projection{
};
// Specialization for no index => Empty tuple
template<>
template<typename... T>
class Projection<std::tuple<T...>>{
typedef std::tuple<T...> InputTuple;
typedef std::tuple<> Tuple;
};
// Specialization for one or more parameters
template<size_t Index1, size_t... others>
template<typename... T>
class Projection<std::tuple<T...>,Index1,others...>{
typedef std::tuple<T...> InputTuple;
// The type of a projection with one column less
typedef Projection<std::tuple<T...>,others...> TupleMinusOne;
// The result type is the catenation of TupleMinusOne plus the column projected in this step
typedef decltype(std::tuple_cat(std::make_tuple(std::get<Index1>(InputTuple())),typename TupleMinusOne::Tuple())) Tuple;
};
This compiles. The base case with the empty tuple also works, i.e.:
Projection<std::tuple<int,std::string>>::Tuple t;
results in t
being an empty tuple. However, the recursion case does not compile:
Projection<std::tuple<int,std::string>,1>::Tuple t;
I get the following error:
Test.cpp:79:1: error: ‘Tuple’ is not a member of ‘Projection<std::tuple<int, float>, 1ul>’
so it seems that the recursive case is not recognized, but why?
Upvotes: 3
Views: 901
Reputation: 217135
You may use the following:
#define Return(ret) decltype(ret) { return ret; }
template<std::size_t... Is, typename T>
auto project(const T& t) -> Return(std::make_tuple(std::get<Is>(t)...))
Upvotes: 1
Reputation: 157324
Recursive templates are very rarely necessary; a pack expansion is usually clearer and simpler. In this case just use tuple_element
:
template<typename T, size_t... indexes>
class Projection{
public:
using Tuple = std::tuple<typename std::tuple_element<indexes, T>::type...>;
};
Ditto for project
:
template<size_t... indexes, typename T>
auto project(const T &t) -> typename Projection<T, indexes...>::Tuple {
return typename Projection<T, indexes...>::Tuple(std::get<indexes>(t)...);
}
Upvotes: 3