Skip to content

Instantly share code, notes, and snippets.

@vladiant
Created November 4, 2025 19:23
Show Gist options
  • Select an option

  • Save vladiant/8f53666b07e96cb4857c3b3977326095 to your computer and use it in GitHub Desktop.

Select an option

Save vladiant/8f53666b07e96cb4857c3b3977326095 to your computer and use it in GitHub Desktop.
C++ tuple iteration 2
#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);
}
#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);
}
#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);
}
#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"));
}
#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);
}
// 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() {}
#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 << ")";
}
#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);
}
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