为多个元组的第n个参数调用lambda吗?

问题描述

我正在尝试编写一个代码,该代码使用从可变的元组集中提取的输入参数来调用lambda。但是,我的尝试无法编译:

#include <iostream>
#include <tuple>
#include <utility>
#include <type_traits>

template <typename ...>
struct first_of;

template <typename T,typename ... Args>
struct first_of<T,Args...> {
    using type = std::decay_t<T>;
};

template <typename T>
struct first_of<T> {
    using type = std::decay_t<T>;
};

template <typename ... T>
using first_of_t = typename first_of<T...>::type;

template <typename Fn,typename... Tuples,std::size_t... Idxs>
void run_impl(Fn&& fn,std::index_sequence<Idxs...>,Tuples... t) {
  auto temp = {(fn(std::get<Idxs>(t)...),true)...};
  (void)temp;
}

template <typename Fn,typename... Tuples>
void run(Fn&& fn,Tuples&&... tuples) {
  run_impl(std::forward<Fn>(fn),std::make_index_sequence<std::tuple_size<first_of_t<Tuples...>>::value>{},std::forward<Tuples>(tuples)...);
}

int main() {
    auto a = std::make_tuple(1,2.34,"one");
    auto b = std::make_tuple(32,5.34,"two");

    auto print = [](auto& f,auto& g) { std::cout << f << "," << g << std::endl; };
    run(print,a,b);
}

我期望以下输出

1,32
2.34,5.34
一,二

我正在使用c ++ 14,因此很遗憾,没有折叠表达式。 这是该代码的Godbolt链接https://godbolt.org/z/G19n5z

解决方法

最简单的方法是添加间接层,让run_impl委托给另一个进行实际调用的函数。我冒昧地将您的函数重命名为call_transposed()

template <std::size_t I,typename Fn,typename... Tuples>
void call_with_nth(Fn&& fn,Tuples&&... t) {
    fn(std::get<I>(std::forward<Tuples>(t))...);
}

template <typename Fn,std::size_t... Idxs,typename... Tuples>
void call_transposed_impl(Fn&& fn,std::index_sequence<Idxs...>,Tuples&&... t) {
  auto temp = {(call_with_nth<Idxs>(fn,std::forward<Tuples>(t)...),true)...};
  (void)temp;
}

template <typename Fn,typename... Tuples>
void call_transposed(Fn&& fn,Tuples&&... tuples) {
  call_transposed_impl(
      std::forward<Fn>(fn),std::make_index_sequence<std::tuple_size<first_of_t<Tuples...>>::value>{},std::forward<Tuples>(tuples)...);
}

Godbolt link

我不确定您的代码为什么不起作用,但是我怀疑std::get<Idxs>(t)...试图同时扩展两个包Idxst,使您陷入困境没有包以后扩展。该代码通过一次只处理一个包装来避免该问题。