From 3d090e7c6fc4caa2fe26b212f44a8ac2581e69c2 Mon Sep 17 00:00:00 2001 From: Lena <23459846+Baduit@users.noreply.github.com> Date: Fri, 13 Sep 2024 10:57:49 +0200 Subject: [PATCH] Add function for_each_field_with_name (#171) --- doc/pfr.qbk | 3 ++ example/quick_examples.cpp | 29 +++++++++++++++++ include/boost/pfr/core_name.hpp | 23 +++++++++++++- .../boost/pfr/detail/core_name14_disabled.hpp | 9 ++++++ .../boost/pfr/detail/core_name20_static.hpp | 17 ++++++++++ .../run/for_each_field_with_name.cpp | 31 +++++++++++++++++++ 6 files changed, 111 insertions(+), 1 deletion(-) create mode 100644 test/core_name/run/for_each_field_with_name.cpp diff --git a/doc/pfr.qbk b/doc/pfr.qbk index 567d2e9..c60bff4 100644 --- a/doc/pfr.qbk +++ b/doc/pfr.qbk @@ -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] ] diff --git a/example/quick_examples.cpp b/example/quick_examples.cpp index 7dd5734..0a0684e 100644 --- a/example/quick_examples.cpp +++ b/example/quick_examples.cpp @@ -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': +// 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 diff --git a/include/boost/pfr/core_name.hpp b/include/boost/pfr/core_name.hpp index 0b11d54..7b73e3d 100644 --- a/include/boost/pfr/core_name.hpp +++ b/include/boost/pfr/core_name.hpp @@ -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` +/// +/// \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 +constexpr void for_each_field_with_name(T&& value, F&& func) { + return boost::pfr::detail::for_each_field_with_name(std::forward(value), std::forward(func)); +} + BOOST_PFR_END_MODULE_EXPORT }} // namespace boost::pfr #endif // BOOST_PFR_CORE_NAME_HPP - diff --git a/include/boost/pfr/detail/core_name14_disabled.hpp b/include/boost/pfr/detail/core_name14_disabled.hpp index 115e838..e1904f0 100644 --- a/include/boost/pfr/detail/core_name14_disabled.hpp +++ b/include/boost/pfr/detail/core_name14_disabled.hpp @@ -37,6 +37,15 @@ constexpr auto tie_as_names_tuple() noexcept { return detail::sequence_tuple::make_sequence_tuple(); } + +template +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 diff --git a/include/boost/pfr/detail/core_name20_static.hpp b/include/boost/pfr/detail/core_name20_static.hpp index 8b8f470..40804fc 100644 --- a/include/boost/pfr/detail/core_name20_static.hpp +++ b/include/boost/pfr/detail/core_name20_static.hpp @@ -12,6 +12,7 @@ #define BOOST_PFR_DETAIL_CORE_NAME20_STATIC_HPP #pragma once +#include #include #include #include @@ -241,6 +242,22 @@ constexpr auto tie_as_names_tuple() noexcept { return detail::tie_as_names_tuple_impl(detail::make_index_sequence()>{}); } +template +constexpr void for_each_field_with_name(T&& value, F&& func) { + return boost::pfr::for_each_field( + std::forward(value), + [f = std::forward(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); + } else { + f(name, std::forward(field)); + } + }); +} + }}} // namespace boost::pfr::detail #endif // BOOST_PFR_DETAIL_CORE_NAME20_STATIC_HPP diff --git a/test/core_name/run/for_each_field_with_name.cpp b/test/core_name/run/for_each_field_with_name.cpp new file mode 100644 index 0000000..c17d9c1 --- /dev/null +++ b/test/core_name/run/for_each_field_with_name.cpp @@ -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 +#include + +#include +#include + + +struct SimpleStruct { + char c; + std::string str; +}; + + +int main () { + std::map 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(); +}