Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Iterate over aggregate fields with the name #171

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions doc/pfr.qbk
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,9 @@ Boost.PFR is a header only library that does not depend on Boost. You can just c

[funcref boost::pfr::io]
]
][
[ [pfr_quick_examples_for_each_with_name] ]
[ [funcref boost::pfr::for_each_field_with_name] ]
][
[ [pfr_quick_examples_functions_for] ]
[ [macroref BOOST_PFR_FUNCTIONS_FOR] ]
Expand Down
29 changes: 29 additions & 0 deletions example/quick_examples.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,35 @@ void test_examples() {
}


// Disabling for MSVC as it gives a hard error on using local types:
//
// error C7631:
// 'boost::pfr::detail::do_not_use_PFR_with_local_types<test_examples::sample>':
// variable with internal linkage declared but not defined
#if BOOST_PFR_CORE_NAME_ENABLED && BOOST_PFR_USE_CPP17 && !defined(_MSC_VER)
{
//[pfr_quick_examples_for_each_with_name
// Print the name and value
// of each element of the structure

struct test {
int n;
std::string str;
};

test var{42, "Hello, World!"};

// Outputs:
// n: 42
// str: Hello, World!
boost::pfr::for_each_field_with_name(var,
[](std::string_view name, const auto& value) {
std::cout << name << ": " << value << std::endl;
});
//]
}
#endif

{
//[pfr_quick_examples_tuple_size
// Getting fields count of some structure
Expand Down
23 changes: 22 additions & 1 deletion include/boost/pfr/core_name.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,30 @@ names_as_array() noexcept {
);
}


/// Calls `func` for each field with its name of a `value`
///
/// \param func must have one of the following signatures:
/// * any_return_type func(std::string_view name, U&& field) // field of value is perfect forwarded to function
/// * any_return_type func(std::string_view name, U&& field, std::size_t i)
/// * any_return_type func(std::string_view name, U&& value, I i) // Here I is an `std::integral_constant<size_t, field_index>`
///
/// \param value To each field of this variable will be the `func` applied.
///
/// \b Example:
/// \code
/// struct Toto { int a; char c; };
/// Toto t {5, 'c'};
/// auto print = [](std::string_view name, const auto& value){ std::cout << "Name: " << name << " Value: " << value << std::endl; };
/// for_each_field_with_name(t, print);
/// \endcode
template <class T, class F>
constexpr void for_each_field_with_name(T&& value, F&& func) {
return boost::pfr::detail::for_each_field_with_name(std::forward<T>(value), std::forward<F>(func));
}

BOOST_PFR_END_MODULE_EXPORT

}} // namespace boost::pfr

#endif // BOOST_PFR_CORE_NAME_HPP

9 changes: 9 additions & 0 deletions include/boost/pfr/detail/core_name14_disabled.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,15 @@ constexpr auto tie_as_names_tuple() noexcept {
return detail::sequence_tuple::make_sequence_tuple();
}


template <class T, class F>
constexpr void for_each_field_with_name(T&& value, F&& func) {
static_assert(
sizeof(T) && false,
"====================> Boost.PFR: Field's names extracting functionality requires C++20."
);
}

}}} // namespace boost::pfr::detail

#endif // BOOST_PFR_DETAIL_CORE_NAME14_DISABLED_HPP
Expand Down
17 changes: 17 additions & 0 deletions include/boost/pfr/detail/core_name20_static.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#define BOOST_PFR_DETAIL_CORE_NAME20_STATIC_HPP
#pragma once

#include <boost/pfr/core.hpp>
#include <boost/pfr/detail/config.hpp>
#include <boost/pfr/detail/core.hpp>
#include <boost/pfr/detail/sequence_tuple.hpp>
Expand Down Expand Up @@ -241,6 +242,22 @@ constexpr auto tie_as_names_tuple() noexcept {
return detail::tie_as_names_tuple_impl<T>(detail::make_index_sequence<detail::fields_count<T>()>{});
}

template <class T, class F>
constexpr void for_each_field_with_name(T&& value, F&& func) {
return boost::pfr::for_each_field(
std::forward<T>(value),
[f = std::forward<F>(func)](auto&& field, auto index) mutable {
using IndexType = decltype(index);
using FieldType = decltype(field);
constexpr auto name = boost::pfr::detail::get_name<std::remove_reference_t<T>, IndexType::value>();
if constexpr (std::is_invocable_v<F, std::string_view, FieldType, IndexType>) {
f(name, std::forward<FieldType>(field), index);
} else {
f(name, std::forward<FieldType>(field));
}
});
}

}}} // namespace boost::pfr::detail

#endif // BOOST_PFR_DETAIL_CORE_NAME20_STATIC_HPP
Expand Down
31 changes: 31 additions & 0 deletions test/core_name/run/for_each_field_with_name.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Copyright (c) 2016-2024 Lena Bertho
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

#include <map>
#include <string>

#include <boost/pfr/core_name.hpp>
#include <boost/core/lightweight_test.hpp>


struct SimpleStruct {
char c;
std::string str;
};


int main () {
std::map<std::string, std::string> m;
auto fill = [&m](std::string_view name, const auto& value){
m[std::string(name)] = value;
};

boost::pfr::for_each_field_with_name(SimpleStruct{ 'e', "test"}, fill);
BOOST_TEST_EQ(m.size(), 2);
BOOST_TEST_EQ(m["c"], "e");
BOOST_TEST_EQ(m["str"], "test");

return boost::report_errors();
}
Loading