Skip to content

Commit 3d090e7

Browse files
authored
Add function for_each_field_with_name (#171)
1 parent e1e908e commit 3d090e7

File tree

6 files changed

+111
-1
lines changed

6 files changed

+111
-1
lines changed

Diff for: doc/pfr.qbk

+3
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,9 @@ Boost.PFR is a header only library that does not depend on Boost. You can just c
230230

231231
[funcref boost::pfr::io]
232232
]
233+
][
234+
[ [pfr_quick_examples_for_each_with_name] ]
235+
[ [funcref boost::pfr::for_each_field_with_name] ]
233236
][
234237
[ [pfr_quick_examples_functions_for] ]
235238
[ [macroref BOOST_PFR_FUNCTIONS_FOR] ]

Diff for: example/quick_examples.cpp

+29
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,35 @@ void test_examples() {
7777
}
7878

7979

80+
// Disabling for MSVC as it gives a hard error on using local types:
81+
//
82+
// error C7631:
83+
// 'boost::pfr::detail::do_not_use_PFR_with_local_types<test_examples::sample>':
84+
// variable with internal linkage declared but not defined
85+
#if BOOST_PFR_CORE_NAME_ENABLED && BOOST_PFR_USE_CPP17 && !defined(_MSC_VER)
86+
{
87+
//[pfr_quick_examples_for_each_with_name
88+
// Print the name and value
89+
// of each element of the structure
90+
91+
struct test {
92+
int n;
93+
std::string str;
94+
};
95+
96+
test var{42, "Hello, World!"};
97+
98+
// Outputs:
99+
// n: 42
100+
// str: Hello, World!
101+
boost::pfr::for_each_field_with_name(var,
102+
[](std::string_view name, const auto& value) {
103+
std::cout << name << ": " << value << std::endl;
104+
});
105+
//]
106+
}
107+
#endif
108+
80109
{
81110
//[pfr_quick_examples_tuple_size
82111
// Getting fields count of some structure

Diff for: include/boost/pfr/core_name.hpp

+22-1
Original file line numberDiff line numberDiff line change
@@ -84,9 +84,30 @@ names_as_array() noexcept {
8484
);
8585
}
8686

87+
88+
/// Calls `func` for each field with its name of a `value`
89+
///
90+
/// \param func must have one of the following signatures:
91+
/// * any_return_type func(std::string_view name, U&& field) // field of value is perfect forwarded to function
92+
/// * any_return_type func(std::string_view name, U&& field, std::size_t i)
93+
/// * any_return_type func(std::string_view name, U&& value, I i) // Here I is an `std::integral_constant<size_t, field_index>`
94+
///
95+
/// \param value To each field of this variable will be the `func` applied.
96+
///
97+
/// \b Example:
98+
/// \code
99+
/// struct Toto { int a; char c; };
100+
/// Toto t {5, 'c'};
101+
/// auto print = [](std::string_view name, const auto& value){ std::cout << "Name: " << name << " Value: " << value << std::endl; };
102+
/// for_each_field_with_name(t, print);
103+
/// \endcode
104+
template <class T, class F>
105+
constexpr void for_each_field_with_name(T&& value, F&& func) {
106+
return boost::pfr::detail::for_each_field_with_name(std::forward<T>(value), std::forward<F>(func));
107+
}
108+
87109
BOOST_PFR_END_MODULE_EXPORT
88110

89111
}} // namespace boost::pfr
90112

91113
#endif // BOOST_PFR_CORE_NAME_HPP
92-

Diff for: include/boost/pfr/detail/core_name14_disabled.hpp

+9
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,15 @@ constexpr auto tie_as_names_tuple() noexcept {
3737
return detail::sequence_tuple::make_sequence_tuple();
3838
}
3939

40+
41+
template <class T, class F>
42+
constexpr void for_each_field_with_name(T&& value, F&& func) {
43+
static_assert(
44+
sizeof(T) && false,
45+
"====================> Boost.PFR: Field's names extracting functionality requires C++20."
46+
);
47+
}
48+
4049
}}} // namespace boost::pfr::detail
4150

4251
#endif // BOOST_PFR_DETAIL_CORE_NAME14_DISABLED_HPP

Diff for: include/boost/pfr/detail/core_name20_static.hpp

+17
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#define BOOST_PFR_DETAIL_CORE_NAME20_STATIC_HPP
1313
#pragma once
1414

15+
#include <boost/pfr/core.hpp>
1516
#include <boost/pfr/detail/config.hpp>
1617
#include <boost/pfr/detail/core.hpp>
1718
#include <boost/pfr/detail/sequence_tuple.hpp>
@@ -241,6 +242,22 @@ constexpr auto tie_as_names_tuple() noexcept {
241242
return detail::tie_as_names_tuple_impl<T>(detail::make_index_sequence<detail::fields_count<T>()>{});
242243
}
243244

245+
template <class T, class F>
246+
constexpr void for_each_field_with_name(T&& value, F&& func) {
247+
return boost::pfr::for_each_field(
248+
std::forward<T>(value),
249+
[f = std::forward<F>(func)](auto&& field, auto index) mutable {
250+
using IndexType = decltype(index);
251+
using FieldType = decltype(field);
252+
constexpr auto name = boost::pfr::detail::get_name<std::remove_reference_t<T>, IndexType::value>();
253+
if constexpr (std::is_invocable_v<F, std::string_view, FieldType, IndexType>) {
254+
f(name, std::forward<FieldType>(field), index);
255+
} else {
256+
f(name, std::forward<FieldType>(field));
257+
}
258+
});
259+
}
260+
244261
}}} // namespace boost::pfr::detail
245262

246263
#endif // BOOST_PFR_DETAIL_CORE_NAME20_STATIC_HPP

Diff for: test/core_name/run/for_each_field_with_name.cpp

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// Copyright (c) 2016-2024 Lena Bertho
2+
//
3+
// Distributed under the Boost Software License, Version 1.0. (See accompanying
4+
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5+
6+
#include <map>
7+
#include <string>
8+
9+
#include <boost/pfr/core_name.hpp>
10+
#include <boost/core/lightweight_test.hpp>
11+
12+
13+
struct SimpleStruct {
14+
char c;
15+
std::string str;
16+
};
17+
18+
19+
int main () {
20+
std::map<std::string, std::string> m;
21+
auto fill = [&m](std::string_view name, const auto& value){
22+
m[std::string(name)] = value;
23+
};
24+
25+
boost::pfr::for_each_field_with_name(SimpleStruct{ 'e', "test"}, fill);
26+
BOOST_TEST_EQ(m.size(), 2);
27+
BOOST_TEST_EQ(m["c"], "e");
28+
BOOST_TEST_EQ(m["str"], "test");
29+
30+
return boost::report_errors();
31+
}

0 commit comments

Comments
 (0)