等价于std :: transform的元组

Nik*_*iou 9 c++ tuples template-meta-programming variadic-templates

我想要一个像std::transform元组一样的函数.基本上要实现的功能是

template<size_t From, size_t To, class Tuple, class Func>
void tuple_transform(Tuple&& source, Tuple&& target, Func f)
{
    // elements <From, To> of `target` ti become `f(si)`, where
    // si is the corresponding element of `source`
};
Run Code Online (Sandbox Code Playgroud)

我认为,要实现这一点,我需要一个编译时整数范围结构,的概括std::index_sequence,我已经实现了它在这里cti::range.我也相信这种类型的编译时间遍历在这里是理想的:

template<class Func, class Tuple, size_t...Is>
void for_each_in_tuple(Func f, Tuple&& tuple, std::index_sequence<Is...>){
    using expander = int[];
    (void)expander { 0, ((void)f(std::get<Is>(std::forward<Tuple>(tuple))), 0)... };
}

template<class Func, class Tuple>
void for_each_in_tuple(Func f, Tuple&& tuple){
    for_each_in_tuple(f, std::forward<Tuple>(tuple),
               std::make_index_sequence<std::tuple_size<std::decay_t<Tuple>>::value>());
}
Run Code Online (Sandbox Code Playgroud)

任何人都可以帮我实现吗?


注意:关于突变功能的类型

@MohitJain在代码链接(tuple_transform)中就像没有考虑到这一点(Func只有一种类型).如果这样解决了,我可以通过传递模板模板参数来轻松扩展它,template<class> class Func并强制我的转换类型是这样的

template<typename T>
struct Func
{
    static void apply(T& val) { ... }
}
Run Code Online (Sandbox Code Playgroud)

然后在元组变换体内,每个变换函数可以调用如下:

get<I>(target) = func<typename tuple_element<I, Tuple>::type>::apply(get<I>(source))
Run Code Online (Sandbox Code Playgroud)

编辑

刚刚发表了一段闪电般的话题@ accu 2015.以上是演示结束时的CodeKata.我将离开这里的演示文稿,希望它对任何实现尝试都有帮助(我认为几乎所有需要的工具都会出现,所以我们会有更多的尝试)

Tar*_*ama 5

这是一个使用index_rangefrom here的解决方案。

template<size_t SN, size_t DN, class TSrc, class TDest, class Func>
void tuple_call_assign(TSrc&& source, TDest& target, Func f)
{
    std::get<DN>(target) = f(std::get<SN>(std::forward<TSrc>(source))); 
}

template<size_t From, size_t To, class TSrc, class TDest, class Func, size_t...Is, size_t...DIs>
void tuple_transform(TSrc&& source, TDest& target, Func f,
                     std::index_sequence<Is...>, std::index_sequence<DIs...>)
{
    using expander = int[];
    (void)expander { 0, (tuple_call_assign<Is,DIs>(std::forward<TSrc>(source),target,f), 0)... };
}

template<size_t From, size_t To, size_t FromDest, class TSrc, class TDest, class Func>
void tuple_transform(TSrc&& source, TDest& target, Func f)
{
    static_assert(To > From, "Range must be increasing");
    static_assert(To <= std::tuple_size<std::decay_t<TSrc>>::value+1, 
        "Range must be valid for source tuple");
    constexpr size_t RangeSize = To-From;
    static_assert(FromDest+RangeSize <= std::tuple_size<std::decay_t<TDest>>::value, 
        "Range must be valid for target tuple");

    tuple_transform<From,To>(std::forward<TSrc>(source), target, f,
                    index_range<From,To>(), index_range<FromDest, FromDest+RangeSize>());
}
Run Code Online (Sandbox Code Playgroud)

演示

这需要第三个模板参数来指定要转换为目标元组的起始索引。