Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

is this boost::tuple code convertible to pure std:: standard library code?

Is the following boost code convertible to pure c++11 standard libraries?

I see std::tuple and std::for_each but I can't seem to get them to play with each other.

I am currently using gcc 4.7.2.

CODE

#include <string>
#include <algorithm>
#include <iostream>

#include <boost/fusion/algorithm/iteration/for_each.hpp>
#include <boost/fusion/include/boost_tuple.hpp>

struct DoOutput
{
    template<typename T>
    void operator()(T const& t) const
    {
            std::cerr << t << std::endl;
    }

    void operator()(std::string const& t) const
    {
            std::cerr << "'" << t << "'" << std::endl;
    }
};

int
main( int argc, char* argv[] )
{
    boost::tuple< std::string, int > t = boost::make_tuple( "foo", 42 );
    boost::fusion::for_each( t, DoOutput() );

    return 0;
}
like image 416
kfmfe04 Avatar asked Sep 10 '26 22:09

kfmfe04


1 Answers

No, the code is not directly convertible.

Boost.Fusion is a library for working with tuples, so its for_each works with tuples, i.e. a structure with zero or more heterogeneous types. std::for_each works with iterator ranges, which are ranges of values of homogeneous type.

Using something like index_tuple.h you can change it to this:

struct sink {
  template<typename... T>
    sink(T&&...) { }
};

template<typename T, typename F>
  int apply(T&& t, F& f)
  {
    f(std::forward<T>(t));
    return 0;
  }

template<typename Tuple, typename F, unsigned... Indices>
  void apply(Tuple&& t, F&& f, index_tuple<Indices...>)
  {
    sink{ apply(std::get<Indices>(std::forward<Tuple>(t)), f)... };
  }

int main()
{
  std::tuple< std::string, int > t = std::make_tuple( "foo", 42 );
  apply(t, DoOutput(), make_index_tuple<std::tuple_size<decltype(t)>::value>::type() );
}

This creates a type index_tuple<0,1> and calls apply, which deduces the parameter pack Indices as {0, 1} and then expands that pack as:

sink{ apply(std::get<0>(t), f), apply(std::get<1>(t), f) };

where f is a function object of type DoOutput, and each apply calls f(tn)

Initializing the temporary sink is only needed because you can't expand a parameter pack in an expression, e.g. this isn't valid:

    f(std::get<Indices>(t))...;

So instead the pack is expanded as the initializer list to an object's constructor, which also guarantees that each element of the pack expansion is evaluated in order.

like image 81
Jonathan Wakely Avatar answered Sep 12 '26 11:09

Jonathan Wakely