Created
November 4, 2025 19:23
-
-
Save vladiant/8f53666b07e96cb4857c3b3977326095 to your computer and use it in GitHub Desktop.
C++ tuple iteration 2
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <iostream> | |
| #include <tuple> | |
| // basic printing | |
| template <typename TupleT, std::size_t... Is> | |
| void printTupleImp(const TupleT& tp, std::index_sequence<Is...>) { | |
| size_t index = 0; | |
| auto printElem = [&index](const auto& x) { | |
| if (index++ > 0) | |
| std::cout << ", "; | |
| std::cout << x; | |
| }; | |
| std::cout << "("; | |
| (printElem(std::get<Is>(tp)), ...); | |
| std::cout << ")"; | |
| } | |
| template <typename TupleT, std::size_t TupSize = std::tuple_size_v<TupleT>> | |
| void printTuple(const TupleT& tp) { | |
| printTupleImp(tp, std::make_index_sequence<TupSize>{}); | |
| } | |
| template <typename TupleT, typename Fn, std::size_t... Is> | |
| void for_each_tuple_impl(TupleT&& tp, Fn&& fn, std::index_sequence<Is...>) { | |
| (fn(std::get<Is>(std::forward<TupleT>(tp))), ...); | |
| } | |
| template <typename TupleT, typename Fn, std::size_t TupSize = std::tuple_size_v<std::remove_cvref_t<TupleT>>> | |
| void for_each_tuple(TupleT&& tp, Fn&& fn) { | |
| for_each_tuple_impl(std::forward<TupleT>(tp), std::forward<Fn>(fn), std::make_index_sequence<TupSize>{}); | |
| } | |
| template <typename TupleT, typename Fn> | |
| void for_each_tuple2(TupleT&& tp, Fn&& fn) { | |
| std::apply | |
| ( | |
| [&fn]<typename ...T>(T&& ...args) | |
| { | |
| (fn(std::forward<T>(args)), ...); | |
| }, std::forward<TupleT>(tp) | |
| ); | |
| } | |
| int main() { | |
| std::tuple tp { 10, 20, 30.0 }; | |
| printTuple(tp); | |
| for_each_tuple2(tp, [](auto&& x){ | |
| x*=2; | |
| }); | |
| printTuple(tp); | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <iostream> | |
| #include <tuple> | |
| // basic printing | |
| template <typename TupleT, std::size_t... Is> | |
| void printTupleImp(const TupleT& tp, std::index_sequence<Is...>) { | |
| size_t index = 0; | |
| auto printElem = [&index](const auto& x) { | |
| if (index++ > 0) | |
| std::cout << ", "; | |
| std::cout << x; | |
| }; | |
| std::cout << "("; | |
| (printElem(std::get<Is>(tp)), ...); | |
| std::cout << ")"; | |
| } | |
| template <typename TupleT, std::size_t TupSize = std::tuple_size_v<TupleT>> | |
| void printTuple(const TupleT& tp) { | |
| printTupleImp(tp, std::make_index_sequence<TupSize>{}); | |
| } | |
| template <typename TupleT, typename Fn, std::size_t... Is> | |
| void for_each_tuple_impl(TupleT&& tp, Fn&& fn, std::index_sequence<Is...>) { | |
| (fn(std::get<Is>(std::forward<TupleT>(tp))), ...); | |
| } | |
| template <typename TupleT, typename Fn, std::size_t TupSize = std::tuple_size_v<std::remove_cvref_t<TupleT>>> | |
| void for_each_tuple(TupleT&& tp, Fn&& fn) { | |
| for_each_tuple_impl(std::forward<TupleT>(tp), std::forward<Fn>(fn), std::make_index_sequence<TupSize>{}); | |
| } | |
| template <typename TupleT, typename Fn> | |
| void for_each_tuple2(TupleT&& tp, Fn&& fn) { | |
| std::apply | |
| ( | |
| [&fn](auto&& ...args) | |
| { | |
| (fn(std::forward<decltype(args)>(args)), ...); | |
| }, std::forward<TupleT>(tp) | |
| ); | |
| } | |
| int main() { | |
| std::tuple tp { 10, 20, 30.0 }; | |
| printTuple(tp); | |
| for_each_tuple2(tp, [](auto&& x){ | |
| x*=2; | |
| }); | |
| printTuple(tp); | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <iostream> | |
| #include <tuple> | |
| // basic printing | |
| template <typename TupleT, std::size_t... Is> | |
| void printTupleImp(const TupleT& tp, std::index_sequence<Is...>) { | |
| size_t index = 0; | |
| auto printElem = [&index](const auto& x) { | |
| if (index++ > 0) | |
| std::cout << ", "; | |
| std::cout << x; | |
| }; | |
| std::cout << "("; | |
| (printElem(std::get<Is>(tp)), ...); | |
| std::cout << ")"; | |
| } | |
| template <typename TupleT, std::size_t TupSize = std::tuple_size_v<TupleT>> | |
| void printTuple(const TupleT& tp) { | |
| printTupleImp(tp, std::make_index_sequence<TupSize>{}); | |
| } | |
| template <typename TupleT, typename Fn, std::size_t... Is> | |
| void for_each_tuple_impl(TupleT&& tp, Fn&& fn, std::index_sequence<Is...>) { | |
| (fn(std::get<Is>(std::forward<TupleT>(tp))), ...); | |
| } | |
| template <typename TupleT, typename Fn, std::size_t TupSize = std::tuple_size_v<std::remove_cvref_t<TupleT>>> | |
| void for_each_tuple(TupleT&& tp, Fn&& fn) { | |
| for_each_tuple_impl(std::forward<TupleT>(tp), std::forward<Fn>(fn), std::make_index_sequence<TupSize>{}); | |
| } | |
| template <typename TupleT, typename Fn> | |
| void for_each_tuple2(TupleT&& tp, Fn&& fn) { | |
| std::apply | |
| ( | |
| [&fn]<typename ...T>(T&& ...args) | |
| { | |
| (fn(std::forward<T>(args)), ...); | |
| }, std::forward<TupleT>(tp) | |
| ); | |
| } | |
| template <typename TupleT, typename Fn> | |
| [[nodiscard]] auto transform_tuple(TupleT&& tp, Fn&& fn) { | |
| return std::apply | |
| ( | |
| [&fn]<typename ...T>(T&& ...args) | |
| { | |
| return std::make_tuple(fn(std::forward<T>(args))...); | |
| }, std::forward<TupleT>(tp) | |
| ); | |
| } | |
| int main() { | |
| std::tuple tp { 10, 20, 30.0 }; | |
| auto printElem = [](const auto& x) { std::cout << x << '\n'; }; | |
| for_each_tuple2(tp, printElem); | |
| for_each_tuple2(tp, [](auto&& x){ | |
| x*=2; | |
| }); | |
| std::cout << "after modiication: \n"; | |
| for_each_tuple2(tp, printElem); | |
| auto res = transform_tuple(tp, [](const auto& x){ | |
| return x*2; | |
| }); | |
| std::cout << "res: \n"; | |
| for_each_tuple2(res, printElem); | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <tuple> | |
| #include <iostream> | |
| #include <utility> | |
| template <typename Tuple> | |
| void print_tuple(const Tuple& t) { | |
| const auto& [...xs] = t; | |
| bool first = true; | |
| std::cout << "("; | |
| ((std::cout << (std::exchange(first, false) ? "" : ", ") << xs), ...); | |
| std::cout << ")"; | |
| } | |
| int main() { | |
| print_tuple(std::make_tuple(1, 2.2, "hello")); | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <tuple> | |
| #include <iostream> | |
| #include <utility> | |
| template <typename Tuple, typename Fn> | |
| auto transform_tuple(const Tuple& t, Fn&& fn) { | |
| const auto& [...xs] = t; | |
| return std::make_tuple(fn(xs)...); | |
| } | |
| template <typename Tuple> | |
| void print_tuple(const Tuple& t) { | |
| const auto& [...xs] = t; | |
| bool first = true; | |
| std::cout << "("; | |
| ((std::cout << (std::exchange(first, false) ? "" : ", ") << xs), ...); | |
| std::cout << ")"; | |
| } | |
| int main() { | |
| std::tuple tp{1, 2, '1'}; | |
| print_tuple(tp); | |
| auto doubled = transform_tuple(tp, | |
| [](auto x){ return decltype(x)(x * 2); }); | |
| print_tuple(doubled); | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // Requires C++26 with P1061 ("structured bindings can introduce a pack") | |
| #include <array> | |
| #include <tuple> | |
| #include <utility> | |
| // Generic dot product for any tuple-like / array / aggregate supported by structured bindings. | |
| template <class P, class Q> | |
| constexpr auto dot_product(const P& p, const Q& q) { | |
| // Bind all elements of each input into packs. | |
| const auto& [...ps] = p; | |
| const auto& [...qs] = q; | |
| // (Optional) sanity check: both must have the same size | |
| static_assert(sizeof...(ps) == sizeof...(qs), "Mismatched sizes"); | |
| // Elementwise multiply, then fold with + | |
| return ((ps * qs) + ...); | |
| } | |
| // ---- constexpr tests ---- | |
| constexpr bool ok() { | |
| // arrays | |
| constexpr std::array<int, 3> a{1, 2, 3}; | |
| constexpr std::array<int, 3> b{4, 5, 6}; | |
| static_assert(dot_product(a, b) == 32); | |
| // tuples | |
| constexpr auto t1 = std::tuple{1, 2, 3}; | |
| constexpr auto t2 = std::tuple{4, 5, 6}; | |
| static_assert(dot_product(t1, t2) == 32); | |
| // mixed types (int * double → double) | |
| constexpr std::tuple<int, int, int> ti{2, 3, 4}; | |
| constexpr std::tuple<double, double, double> td{0.5, 1.0, 1.5}; | |
| static_assert(dot_product(ti, td) == 2*0.5 + 3*1.0 + 4*1.5); // 0.999... + 3 + 6 = 9.0 | |
| return true; | |
| } | |
| static_assert(ok()); | |
| int main() {} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <tuple> | |
| #include <iostream> | |
| #include <utility> | |
| int main() { | |
| auto tp = std::make_tuple(10, 20, 3.14, "hello"); | |
| std::cout << "("; | |
| bool first = true; | |
| template for (auto e : tp) { | |
| if (!std::exchange(first, false)) std::cout << ", "; | |
| std::cout << e; | |
| } | |
| std::cout << ")"; | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <tuple> | |
| #include <print> | |
| #include <utility> | |
| template <class Tuple> | |
| void print_tuple_expand(const Tuple& t) { | |
| bool first = true; | |
| std::print("("); | |
| template for (const auto& e : t) { | |
| if (!std::exchange(first, false)) { | |
| std::print(", "); | |
| } | |
| std::print("{}", e); | |
| } | |
| std::print(")\n"); | |
| } | |
| template <class Tuple, class Fn> | |
| void for_each_tuple_expand(Tuple&& t, Fn&& fn) { | |
| template for (auto&& e : std::forward<Tuple>(t)) { | |
| fn(std::forward<decltype(e)>(e)); | |
| } | |
| } | |
| int main() { | |
| auto tp = std::make_tuple(10, 20, 3.14); | |
| print_tuple_expand(tp); | |
| for_each_tuple_expand(tp, [](auto& x) {x *= 2;}); | |
| print_tuple_expand(tp); | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| https://www.cppstories.com/2022/tuple-iteration-basics/ | |
| https://www.cppstories.com/2022/tuple-iteration-apply/ | |
| https://www.cppstories.com/2025/tuple-iteration-cpp26/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment