unpacking, function application, and packing tuples in C++0X
What is the best way to write the readvals function in the following code without using Boost? Basically, it should get a tuple, call a specific function of it's elemets and return the generated results as a tuple again.
Is there any C++0X-based Functor definition library for tuples?
template <class T>
struct A
{
A(T _val):val(_val){}
T ret() {return val;}
T val;
};
template <typename... ARGS>
std::tuple<ARGS...> readvals(std::tuple<A<ARGS>...> targ)
{
//???
}
int main(int argc, char **argv)
{
A<int> ai = A<int>(5);
A<char> ac = A<char>('c');
A<double> ad = A<double>(0.5);
std::tuple<A<int>,A<char>,A<double>> at = std::make_tuple(ai,ac,ad);
// assuming proper overloading of "<<" for tuples exists
std::cout << readvals<int,char,double>(at) << std::endl;
// I expect something like (5, c, 0.5) in the output
return 0;
}
I have found questions on SO which deal partly with this problem (tuple unpacking, iterating over tuple elements, etc.), but it seems to me that there should be an easier so开发者_如何学Golution compared to putting together all such solutions.
If I understand correctly, you just want to make a new tuple whose contents are the results of a function applied to the contents of an old tuple? Like so:
std::tuple<A,B,C> result =
std::tuple<A,B,C>(f(std::get<0>(x), f(std::get<1>(x), f(std::get<2>(x));
Is this right? To answer that, I am stealing @Luc Danton's excellent tuple indexer. At the very heart, this construction allows us to write:
std::tuple<Args...> result = std::tuple<Args...>(f(std::get<Indices>(x))...);
Here's how it works: First, the Indices
helper:
#include <tuple>
template<int... Indices>
struct indices {
typedef indices<Indices..., sizeof...(Indices)> next;
};
template<int Size>
struct build_indices {
typedef typename build_indices<Size - 1>::type::next type;
};
template<>
struct build_indices<0> {
typedef indices<> type;
};
template<typename Tuple>
typename build_indices<std::tuple_size<typename std::decay<Tuple>::type>::value>::type
make_indices()
{
return {};
}
Now for the application: We just make a simple, fixed function f
that doubles its input.
template <typename T> T f(const T & t) { return 2*t; }
Let's apply that to a tuple. Here's a hardwired function, but you can easily template that on f
:
template <typename Tuple, int ...Indices>
Tuple apply_f_impl(const Tuple & x, indices<Indices...>)
{
return Tuple(f(std::get<Indices>(x))...);
}
template <typename Tuple>
Tuple apply_f(const Tuple & x)
{
return apply_f_impl(x, make_indices<Tuple>());
}
Finally, the test case:
#include <iostream>
#include "prettyprint.hpp"
int main()
{
std::tuple<int, double, char> x(5, 1.5, 'a');
auto y = apply_f(x);
std::cout << "Before: " << x << ", after: " << y << std::endl;
}
All credits for this should go to Luc, who came up with the self-indexing tuple indexer.
Is this what you are looking for? I hope you can at least use it as a starting point. There are just more ways to approach working with tuples and variadic templates than there are ways that lead to rome...
#include <iostream>
#include <tuple>
template<class T>
struct A
{
T t;
A( const T& t_ ) : t(t_) { }
};
template<class T>
T func( const A<T>& t)
{
std::cout << __PRETTY_FUNCTION__ << " " << t.t << "\n";
return t.t;
}
template<size_t N,class R, class T>
struct genh
{
static void gen( R& ret, const T& t )
{
std::cout << __PRETTY_FUNCTION__ << "\n";
genh<N-1,R,T>::gen(ret,t);
std::get<N>(ret) = func(std::get<N>(t));
}
};
template<class R, class T>
struct genh<0,R,T>
{
static void gen( R& ret, const T& t )
{
std::cout << __PRETTY_FUNCTION__ << "\n";
std::get<0>(ret) = func(std::get<0>(t));
}
};
template<class... T>
std::tuple<T...> readvals( const std::tuple<A<T>...>& targ )
{
std::tuple<T...> ret;
genh<sizeof...(T)-1,std::tuple<T...>,std::tuple<A<T>...>>::gen(ret,targ);
return ret;
}
int main(int argc, const char *argv[])
{
A<int> ai = A<int>(5);
A<char> ac = A<char>('c');
A<double> ad = A<double>(0.5);
std::tuple<A<int>,A<char>,A<double>> at = std::make_tuple(ai,ac,ad);
readvals(at);
return 0;
}
精彩评论