Skip to content
Open
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 @@ -233,6 +233,9 @@ Boost.PFR is a header only library that does not depend on Boost. You can just c
][
[ [pfr_quick_examples_for_each_with_name] ]
[ [funcref boost::pfr::for_each_field_with_name] ]
][
[ [pfr_quick_examples_for_each_name] ]
[ [funcref boost::pfr::for_each_name] ]
][
[ [pfr_quick_examples_functions_for] ]
[ [macroref BOOST_PFR_FUNCTIONS_FOR] ]
Expand Down
20 changes: 20 additions & 0 deletions example/quick_examples.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,26 @@ void test_examples() {
[](std::string_view name, const auto& value) {
std::cout << name << ": " << value << std::endl;
});
//]
}

{
//[pfr_quick_examples_for_each_name
// Iterate over field names and indices of a structure
// without constructing an instance of it.

struct sample {
int f_int;
long f_long;
};

// Outputs:
// 0: f_int
// 1: f_long
boost::pfr::for_each_name<sample>(
[](std::string_view name, auto index) {
std::cout << '\n' << index() << ": " << name;
});
//]
}
#endif
Expand Down
27 changes: 27 additions & 0 deletions include/boost/pfr/core_name.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

#include <boost/pfr/detail/core_name.hpp>

#include <boost/pfr/detail/for_each_name.hpp>
#include <boost/pfr/detail/sequence_tuple.hpp>
#include <boost/pfr/detail/stdarray.hpp>
#include <boost/pfr/detail/make_integer_sequence.hpp>
Expand Down Expand Up @@ -130,6 +131,32 @@ constexpr void for_each_field_with_name(T&& value, F&& func) {
#endif
}

/// Calls `func` for each field name of the \aggregate `T`.
/// \param func must have one of the following signatures:
/// * any_return_type func(std::string_view name)
/// * any_return_type func(std::string_view name, I i) // Here I is an `std::integral_constant<size_t, field_index>`
///
/// \b Example:
/// \code
/// struct my_struct { int i; short s; };
///
/// boost::pfr::for_each_name<my_struct>([](std::string_view name, auto index) {
/// std::cout << index() << ": " << name << '\n'; // Outputs: 0: i 1: s
/// });
/// \endcode
template <class T, class F>
constexpr void for_each_name(F&& func) {
#if BOOST_PFR_CORE_NAME_ENABLED
detail::for_each_name_impl<T>(
func,
detail::make_index_sequence< tuple_size_v<T> >()
);
#else
boost::pfr::detail::report_name_reflection_mising_requirement<T>();
(void)func;
#endif
}

BOOST_PFR_END_MODULE_EXPORT

}} // namespace boost::pfr
Expand Down
39 changes: 39 additions & 0 deletions include/boost/pfr/detail/for_each_name.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#ifndef BOOST_PFR_DETAIL_FOR_EACH_NAME_HPP
#define BOOST_PFR_DETAIL_FOR_EACH_NAME_HPP
#pragma once

#include <boost/pfr/detail/config.hpp>

#include <boost/pfr/detail/core_name.hpp>

#if BOOST_PFR_CORE_NAME_ENABLED

#if !defined(BOOST_PFR_INTERFACE_UNIT)
#include <cstddef>
#include <string_view>
#include <type_traits>
#include <utility>
#endif

namespace boost { namespace pfr { namespace detail {

template <class T, std::size_t I, class F>
constexpr void for_each_name_apply(F& func) {
constexpr std::string_view name = detail::get_name<T, I>();
if constexpr (std::is_invocable_v<F&, std::string_view, std::integral_constant<std::size_t, I>>) {
func(name, std::integral_constant<std::size_t, I>{});
} else {
func(name);
}
}

template <class T, class F, std::size_t... I>
constexpr void for_each_name_impl(F& func, std::index_sequence<I...>) {
(detail::for_each_name_apply<T, I>(func), ...);
}

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

#endif // BOOST_PFR_CORE_NAME_ENABLED

#endif // BOOST_PFR_DETAIL_FOR_EACH_NAME_HPP
62 changes: 62 additions & 0 deletions test/core_name/run/for_each_name.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#include <string>
#include <type_traits>
#include <vector>

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


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

struct EmptyStruct {};

struct stateful_counting_visitor {
std::size_t count = 0;

void operator()(std::string_view /*name*/) { ++count; }
};

int main () {
std::vector<std::string> names;
boost::pfr::for_each_name<SimpleStruct>([&names](std::string_view name) {
names.emplace_back(name);
});
BOOST_TEST_EQ(names.size(), 3);
BOOST_TEST_EQ(names[0], "c");
BOOST_TEST_EQ(names[1], "str");
BOOST_TEST_EQ(names[2], "i");

std::vector<std::string> names_by_index(3);
boost::pfr::for_each_name<SimpleStruct>([&names_by_index](std::string_view name, auto index) {
static_assert(std::is_same_v<
decltype(index),
std::integral_constant<std::size_t, decltype(index)::value>
>);
names_by_index[index] = std::string(name);
BOOST_TEST((name == boost::pfr::get_name<decltype(index)::value, SimpleStruct>()));
});
BOOST_TEST_EQ(names_by_index[0], "c");
BOOST_TEST_EQ(names_by_index[1], "str");
BOOST_TEST_EQ(names_by_index[2], "i");

stateful_counting_visitor counting_visitor;
boost::pfr::for_each_name<SimpleStruct>(counting_visitor);
BOOST_TEST_EQ(counting_visitor.count, 3);

std::size_t empty_count = 0;
boost::pfr::for_each_name<EmptyStruct>([&empty_count](std::string_view) { ++empty_count; });
BOOST_TEST_EQ(empty_count, 0);

constexpr std::size_t constexpr_count = [] {
std::size_t count = 0;
boost::pfr::for_each_name<SimpleStruct>([&count](std::string_view) { ++count; });
return count;
}();
static_assert(constexpr_count == 3);

return boost::report_errors();
}