Question

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 solution compared to putting together all such solutions.

Was it helpful?

Solution

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;
}

OTHER TIPS

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top