Implementing map () and each () over std :: tuple <...> - with the index passed to the functor as a template parameter

After several years of web development, I am working in C ++ again (14) and decided to create a "dynamically typed functional pleasure" with template metaprogramming.

I have implemented map

and each

via tuples:

template <typename Tuple, typename Func, size_t... index>
void tuple_each_internal(Tuple const & tuple, Func func, index_sequence<index...>)
{
    auto res = {
        (func(get<index>(tuple)), nullptr)...
    };
}

template <typename Tuple, typename Func, typename Indices = make_index_sequence<tuple_size<Tuple>::value>>
void tuple_each(Tuple const & tuple, Func func)
{
    tuple_each_internal(tuple, func, Indices());
}

struct demo_functor_each {

    /* Case #1: "Each" callback */
    template <typename T>
    void operator ()(T&& t) { ; }

    /* Case #2: "Each with index as run-time parameter" callback */
    //template <typename T>
    //void operator ()(const size_t index, T&& t) { ; }

    /* Case #3: "Each with index as compile-time parameter" callback */
    //template <typename T, size_t index>
    //void operator ()(T&& t) { ; }

};

void Example_Usage()
{
    tuple<int, bool, string> t;
    tuple_each(t, demo_functor_each());
}

      

And a similar implementation map

.

  • Case # 1 checks the syntax (I haven't tried running it yet).

  • №2 case also checks the syntax checking, with tuple_each_internal

    modified to pass the index as a parameter to the function: func(index, get<index>(tuple))

    .

  • Case # 3 is superior to Case # 2, in which the value index

    can be passed to other templates at compile time (eg get<index>(tuple)

    ), which is not possible in Case # 2.

I was unable to implement case # 3.

Given the signature of the callback:

template <typename T, size_t index>
void operator ()(T&& t) { ; }

      

I tried this like tuple_each_internal

:

auto res = {
    (func<typename tuple_element<index, Tuple>::type, index>(get<index>(tuple)), nullptr)...
};

      

Clang ++ 3.6.1 output:

$ clang++ -std=c++14 tuple_iteration.h

error: expected '(' for function-style cast or type construction

auto res = { (func<typename tuple_element<index, Tuple>::type, index>(get<index>(tuple)), nullptr)... };
                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^

      

g ++ 5.1.0 output:

$ g++ -std=c++14 tuple_iteration.h

error: expected ‘(’ before ‘,’ token

auto res = { (func<typename tuple_element<index, Tuple>::type, index>(get<index>(tuple)), nullptr)... };
                                                             ^

      

+3


source share


2 answers


It should be:

auto res = {
    (func.template operator()<const typename tuple_element<index, Tuple>::type&, index>(get<index>(tuple)),
     nullptr)...
};

      

Live Demo .

Simplification with

/* Case #4: "Each with index as compile-time parameter" callback */
template <size_t index, typename T>
void operator ()(T&& t);

      

where the code becomes:

auto res = {
    (func.template operator()<index>(get<index>(tuple)),
     nullptr)...
};

      



Live Demo

or even

template <size_t N, typename T>
void operator ()(std::integral_constant<std::size_t, N>, T&& t);

      

that leads to

auto res = {
    (func(std::integral_constant<std::size_t, index>{}, get<index>(tuple)),
     nullptr)...
};

      

Live Demo

+2


source


For what it's worth an example of doing something like this in C ++ 17 using folding expressions for the comma operator:



//Example of creating a pack of vectors from a pack of template args, one vector for each type ("rotating" the pack 90 deg)


#include <iostream>
#include <vector>
#include <string>
#include <tuple>
#include <algorithm>
#include <functional>
#include <numeric>
#include <iterator>

#include <utility>//index_sequence
//
//g++ -std=c++1z rotate_pack.cpp -o rotate_pack.exe
//
//
template<typename ...Ts>
struct SOA_State
{

  explicit SOA_State(size_t n):tuple_vecs_(std::vector<Ts>(n, Ts())...)//ok
  {
  }

  //using fold expresions for "," (comma) operator; requires c++17
  //
  template<typename ...Fs,                                         //pack of functor types
       std::size_t ...Is>                                      //pack of tuple indices to fold over
  void transform_pack(const std::tuple<Fs...>& fctr_pack,          //pack of fctrs
              std::tuple<std::vector<Ts>...>& result_pack, //pack of result vectors
              std::index_sequence<Is...>)
  {
    (std::transform(std::begin(std::get<Is>(tuple_vecs_)),std::end(std::get<Is>(tuple_vecs_)),
            std::begin(std::get<Is>(result_pack)),//std::back_inserter?
            std::get<Is>(fctr_pack)), ...);
  }

  //using fold expresions for "," (comma) operator; requires c++17
  //
  template<typename ...Fs,                                         //pack of functor types
       std::size_t ...Is>                                      //pack of tuple indices to fold over
  static
  void foreach_pack(const std::tuple<Fs...>& fctr_pack,            //pack of fctrs
            std::tuple<std::vector<Ts>...>& source_pack,   //pack of result vectors
            std::index_sequence<Is...>)
  {
    (std::for_each(std::begin(std::get<Is>(source_pack)),std::end(std::get<Is>(source_pack)),
           std::get<Is>(fctr_pack)), ...);
  }

private:
  std::tuple<std::vector<Ts>...> tuple_vecs_;//ok
};

int main(void)
{
  size_t n_states = 10;
  SOA_State<int, double, std::string> soa(n_states);

  auto fctr_tuple = std::make_tuple([](const int& v){return v+1;}, [](const double& v){return 2.0*(v+.13);}, [](const std::string& s){return std::string("hello");});
  auto res_tuple = std::make_tuple(std::vector<int>(n_states,0), std::vector<double>(n_states,0.), std::vector<std::string>(n_states,std::string()));
  std::index_sequence_for<int, double, std::string> is;

  //apply transform on pack with results in another pack:
  //
  soa.transform_pack(fctr_tuple, res_tuple, is);

  auto printer_tuple = std::make_tuple([](const int& v){std::cout<<"i:"<<v<<"\n";}, [](const double& v){std::cout<<"d:"<<v<<"\n";}, [](const std::string& s){std::cout<<"s:"<<s<<"\n";});

  //print the results pack:
  //
  SOA_State<int, double, std::string>::foreach_pack(printer_tuple, res_tuple, is);
  std::cout<<"\n";

  std::cout<<"Done!"<<std::endl;
};

      

+1


source







All Articles