如何在C++20中从已有tuple生成新tuple?
问题
已有如下C代码,已创建tuple对象t1,希望对t1的每个元素分别调用f1、f2、f3函数,生成类型为std::tuple<std::string, float, int>的新tuple。请问在C20中是否有实现方式,比如使用std::tuple_cat?
代码示例:
std::string f1(int a) { std::string b = "hello"; return b; } float f2(std::string a) { float b = 2.5f; return b; } int f3(float a) { int b = 4; return b; } int main() { auto t1 = std::make_tuple(1, "a", 1.5f); // 目标新tuple --> std::tuple<std::string, float, int>(f1(1), f2("a"), f3(1.5)); return 0; }
解决方案
C++20里有多种简洁的实现方式,std::tuple_cat其实并不适配这个场景(它主要用于拼接多个tuple),更合适的是用std::apply配合结构化绑定,或者借助编译期索引序列逐个处理元素。
方法1:std::apply + 结构化绑定
利用std::apply展开tuple元素为函数参数的特性,结合结构化绑定直接提取元素并调用对应函数,写法直观易懂:
#include <tuple> #include <string> // 保留原函数定义... int main() { auto t1 = std::make_tuple(1, "a", 1.5f); auto [a, b, c] = t1; auto new_tuple = std::make_tuple(f1(a), f2(b), f3(c)); // new_tuple的类型即为std::tuple<std::string, float, int> return 0; }
方法2:编译期索引序列(通用化方案)
如果需要适配任意长度的tuple,可借助std::make_index_sequence生成编译期索引,实现通用化的逐个元素处理:
#include <tuple> #include <string> #include <utility> // 保留原函数定义... template<typename Tuple, typename... Funcs, std::size_t... Idx> auto apply_each_impl(const Tuple& t, std::tuple<Funcs...> funcs, std::index_sequence<Idx...>) { return std::make_tuple(std::get<Idx>(funcs)(std::get<Idx>(t))...); } template<typename Tuple, typename... Funcs> auto apply_each(const Tuple& t, Funcs&&... funcs) { static_assert(std::tuple_size_v<Tuple> == sizeof...(Funcs), "Tuple元素数量必须与传入函数数量一致"); return apply_each_impl(t, std::make_tuple(std::forward<Funcs>(funcs)...), std::make_index_sequence<std::tuple_size_v<Tuple>>{}); } int main() { auto t1 = std::make_tuple(1, "a", 1.5f); auto new_tuple = apply_each(t1, f1, f2, f3); // new_tuple类型符合要求 return 0; }
关于std::tuple_cat的说明
虽然可以用std::tuple_cat(std::make_tuple(f1(a)), std::make_tuple(f2(b)), std::make_tuple(f3(c)))生成目标tuple,但这种写法需要为每个元素创建临时tuple再拼接,冗余且没必要,远不如上面两种方法简洁。
内容的提问来源于stack exchange,提问作者bharath2438
相关产品推荐
相关产品推荐

