From fe4857ac8be9f53524eb80983046813fd40f6dc3 Mon Sep 17 00:00:00 2001 From: Antony Polukhin Date: Mon, 26 Jan 2026 15:07:39 +0300 Subject: [PATCH 1/2] Allow stateful visitors in for_each_field() --- include/boost/pfr/core.hpp | 2 +- include/boost/pfr/detail/for_each_field.hpp | 4 ++-- test/core/run/for_each_field.cpp | 11 +++++++++++ 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/include/boost/pfr/core.hpp b/include/boost/pfr/core.hpp index d621f273..a4f230cd 100644 --- a/include/boost/pfr/core.hpp +++ b/include/boost/pfr/core.hpp @@ -255,7 +255,7 @@ constexpr auto structure_tie(T&&, std::enable_if_t< std::is_rvalue_reference constexpr void for_each_field(T&& value, F&& func) { - return ::boost::pfr::detail::for_each_field(std::forward(value), std::forward(func)); + ::boost::pfr::detail::for_each_field(std::forward(value), std::forward(func)); } /// \brief std::tie-like function that allows assigning to tied values from aggregates. diff --git a/include/boost/pfr/detail/for_each_field.hpp b/include/boost/pfr/detail/for_each_field.hpp index 33b3ec1f..c2d92ed3 100644 --- a/include/boost/pfr/detail/for_each_field.hpp +++ b/include/boost/pfr/detail/for_each_field.hpp @@ -42,14 +42,14 @@ constexpr void for_each_field(T&& value, F&& func) { ::boost::pfr::detail::for_each_field_dispatcher( value, - [f = std::forward(func)](auto&& t) mutable { + [&func](auto&& t) mutable { // MSVC related workaround. Its lambdas do not capture constexprs. constexpr std::size_t fields_count_val_in_lambda = boost::pfr::detail::fields_count>(); ::boost::pfr::detail::for_each_field_impl( t, - std::forward(f), + std::forward(func), detail::make_index_sequence{}, std::is_rvalue_reference{} ); diff --git a/test/core/run/for_each_field.cpp b/test/core/run/for_each_field.cpp index 031636b4..30001145 100644 --- a/test/core/run/for_each_field.cpp +++ b/test/core/run/for_each_field.cpp @@ -56,6 +56,13 @@ struct simple { struct empty{}; +struct stateful_counting_visitor { + std::size_t count = 0; + + template + void operator()(const T&) { ++count; } +}; + #if BOOST_PFR_USE_CPP17 constexpr std::size_t get_field_count_through_for_each_field() { std::size_t counter = 0; @@ -132,6 +139,10 @@ int main () { }); BOOST_TEST_EQ("", ss.str()); ss.str(""); + + stateful_counting_visitor counting_visitor; + boost::pfr::for_each_field(simple{}, counting_visitor); + BOOST_TEST_EQ(3, counting_visitor.count); return boost::report_errors(); } From 582bf51a7a50bcf1ca34b1612df6ae21da283d21 Mon Sep 17 00:00:00 2001 From: Antony Polukhin Date: Mon, 26 Jan 2026 18:26:28 +0300 Subject: [PATCH 2/2] fix stateful visitation for for_each_field_with_name --- include/boost/pfr/detail/core_name20_static.hpp | 6 +++--- test/core_name/run/for_each_field_with_name.cpp | 10 ++++++++++ 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/include/boost/pfr/detail/core_name20_static.hpp b/include/boost/pfr/detail/core_name20_static.hpp index 4c615904..ba03cac9 100644 --- a/include/boost/pfr/detail/core_name20_static.hpp +++ b/include/boost/pfr/detail/core_name20_static.hpp @@ -245,14 +245,14 @@ template constexpr void for_each_field_with_name(T&& value, F&& func) { return boost::pfr::detail::for_each_field( std::forward(value), - [f = std::forward(func)](auto&& field, auto index) mutable { + [&func](auto&& field, auto index) mutable { using IndexType = decltype(index); using FieldType = decltype(field); constexpr auto name = boost::pfr::detail::get_name, IndexType::value>(); if constexpr (std::is_invocable_v) { - f(name, std::forward(field), index); + std::forward(func)(name, std::forward(field), index); } else { - f(name, std::forward(field)); + std::forward(func)(name, std::forward(field)); } }); } diff --git a/test/core_name/run/for_each_field_with_name.cpp b/test/core_name/run/for_each_field_with_name.cpp index c17d9c19..b071e04e 100644 --- a/test/core_name/run/for_each_field_with_name.cpp +++ b/test/core_name/run/for_each_field_with_name.cpp @@ -15,6 +15,12 @@ struct SimpleStruct { std::string str; }; +struct stateful_counting_visitor { + std::size_t count = 0; + + template + void operator()(std::string_view /*name*/, const T&) { ++count; } +}; int main () { std::map m; @@ -27,5 +33,9 @@ int main () { BOOST_TEST_EQ(m["c"], "e"); BOOST_TEST_EQ(m["str"], "test"); + stateful_counting_visitor counting_visitor; + boost::pfr::for_each_field_with_name(SimpleStruct{}, counting_visitor); + BOOST_TEST_EQ(2, counting_visitor.count); + return boost::report_errors(); }