распаковка, применение функций и упаковка кортежей в C ++ 0X - PullRequest
2 голосов
/ 16 августа 2011

Каков наилучший способ написать функцию readvals в следующем коде без использования Boost?По сути, он должен получить кортеж, вызвать определенную функцию его элементов и снова вернуть сгенерированные результаты в виде кортежа.

Существует ли какая-либо библиотека определений Functor на основе C ++ 0X для кортежей?

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

Я нашел вопросы о SO, которые частично касаются этой проблемы (распаковка кортежа, перебор элементов кортежа и т. Д.), Но мне кажется, что должно быть более простое решение по сравнению со сборкой всех таких решений.

Ответы [ 2 ]

8 голосов
/ 16 августа 2011

Если я правильно понимаю, вы просто хотите создать новый кортеж, содержимое которого является результатом функции, примененной к содержимому старого кортежа?Вот так:

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

Это правильно?Чтобы ответить на это, я краду отличный индексатор кортежей @Luc Danton.В самом сердце эта конструкция позволяет нам написать:

std::tuple<Args...> result = std::tuple<Args...>(f(std::get<Indices>(x))...);

Вот как это работает: во-первых, Indices помощник:

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

Теперь для приложения: мы простосоздадим простую фиксированную функцию f, которая удваивает ввод.

template <typename T> T f(const T & t) { return 2*t; }

Давайте применим это к кортежу.Вот встроенная функция, но вы можете легко создать шаблон, который на 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>());
}

Наконец, контрольный пример:

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

Все кредиты для этого должны идти к Люку, которыйпридумали индексатор кортежей с самоиндексированием.

0 голосов
/ 16 августа 2011

Это то, что вы ищете? Я надеюсь, что вы можете по крайней мере использовать его в качестве отправной точки. Есть только больше способов приблизиться к работе с кортежами и шаблонами с переменными числами, чем есть способы, которые приводят к Риму ...

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