1// Copyright (c) 2016-2024 Antony Polukhin
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#ifndef BOOST_PFR_CORE_HPP
7#define BOOST_PFR_CORE_HPP
8#pragma once
9
10#include <boost/pfr/detail/config.hpp>
11
12#include <boost/pfr/detail/core.hpp>
13
14#include <boost/pfr/detail/sequence_tuple.hpp>
15#include <boost/pfr/detail/stdtuple.hpp>
16#include <boost/pfr/detail/for_each_field_impl.hpp>
17#include <boost/pfr/detail/make_integer_sequence.hpp>
18#include <boost/pfr/detail/tie_from_structure_tuple.hpp>
19
20#include <type_traits>
21#include <utility> // metaprogramming stuff
22
23#include <boost/pfr/tuple_size.hpp>
24
25/// \file boost/pfr/core.hpp
26/// Contains all the basic tuple-like interfaces \forcedlink{get}, \forcedlink{tuple_size}, \forcedlink{tuple_element_t}, and others.
27///
28/// \b Synopsis:
29
30namespace boost { namespace pfr {
31
32/// \brief Returns reference or const reference to a field with index `I` in \aggregate `val`.
33/// Overload taking the type `U` returns reference or const reference to a field
34/// with provided type `U` in \aggregate `val` if there's only one field of such type in `val`.
35///
36/// \b Example:
37/// \code
38/// struct my_struct { int i, short s; };
39/// my_struct s {10, 11};
40///
41/// assert(boost::pfr::get<0>(s) == 10);
42/// boost::pfr::get<1>(s) = 0;
43///
44/// assert(boost::pfr::get<int>(s) == 10);
45/// boost::pfr::get<short>(s) = 11;
46/// \endcode
47template <std::size_t I, class T>
48constexpr decltype(auto) get(const T& val) noexcept {
49 return detail::sequence_tuple::get<I>( detail::tie_as_tuple(val) );
50}
51
52/// \overload get
53template <std::size_t I, class T>
54constexpr decltype(auto) get(T& val
55#if !BOOST_PFR_USE_CPP17
56 , std::enable_if_t<std::is_assignable<T, T>::value>* = nullptr
57#endif
58) noexcept {
59 return detail::sequence_tuple::get<I>( detail::tie_as_tuple(val) );
60}
61
62#if !BOOST_PFR_USE_CPP17
63/// \overload get
64template <std::size_t I, class T>
65constexpr auto get(T&, std::enable_if_t<!std::is_assignable<T, T>::value>* = nullptr) noexcept {
66 static_assert(sizeof(T) && false, "====================> Boost.PFR: Calling boost::pfr::get on non const non assignable type is allowed only in C++17");
67 return 0;
68}
69#endif
70
71
72/// \overload get
73template <std::size_t I, class T>
74constexpr auto get(T&& val, std::enable_if_t< std::is_rvalue_reference<T&&>::value>* = nullptr) noexcept {
75 return std::move(detail::sequence_tuple::get<I>( detail::tie_as_tuple(val) ));
76}
77
78
79/// \overload get
80template <class U, class T>
81constexpr const U& get(const T& val) noexcept {
82 return detail::sequence_tuple::get_by_type_impl<const U&>( detail::tie_as_tuple(val) );
83}
84
85
86/// \overload get
87template <class U, class T>
88constexpr U& get(T& val
89#if !BOOST_PFR_USE_CPP17
90 , std::enable_if_t<std::is_assignable<T, T>::value>* = nullptr
91#endif
92) noexcept {
93 return detail::sequence_tuple::get_by_type_impl<U&>( detail::tie_as_tuple(val) );
94}
95
96#if !BOOST_PFR_USE_CPP17
97/// \overload get
98template <class U, class T>
99constexpr U& get(T&, std::enable_if_t<!std::is_assignable<T, T>::value>* = nullptr) noexcept {
100 static_assert(sizeof(T) && false, "====================> Boost.PFR: Calling boost::pfr::get on non const non assignable type is allowed only in C++17");
101 return 0;
102}
103#endif
104
105
106/// \overload get
107template <class U, class T>
108constexpr U&& get(T&& val, std::enable_if_t< std::is_rvalue_reference<T&&>::value>* = nullptr) noexcept {
109 return std::move(detail::sequence_tuple::get_by_type_impl<U&>( detail::tie_as_tuple(val) ));
110}
111
112
113/// \brief `tuple_element` has a member typedef `type` that returns the type of a field with index I in \aggregate T.
114///
115/// \b Example:
116/// \code
117/// std::vector< boost::pfr::tuple_element<0, my_structure>::type > v;
118/// \endcode
119template <std::size_t I, class T>
120using tuple_element = detail::sequence_tuple::tuple_element<I, decltype( ::boost::pfr::detail::tie_as_tuple(std::declval<T&>()) ) >;
121
122
123/// \brief Type of a field with index `I` in \aggregate `T`.
124///
125/// \b Example:
126/// \code
127/// std::vector< boost::pfr::tuple_element_t<0, my_structure> > v;
128/// \endcode
129template <std::size_t I, class T>
130using tuple_element_t = typename tuple_element<I, T>::type;
131
132
133/// \brief Creates a `std::tuple` from fields of an \aggregate `val`.
134///
135/// \b Example:
136/// \code
137/// struct my_struct { int i, short s; };
138/// my_struct s {10, 11};
139/// std::tuple<int, short> t = boost::pfr::structure_to_tuple(s);
140/// assert(get<0>(t) == 10);
141/// \endcode
142template <class T>
143constexpr auto structure_to_tuple(const T& val) {
144 return detail::make_stdtuple_from_tietuple(
145 detail::tie_as_tuple(val),
146 detail::make_index_sequence< tuple_size_v<T> >()
147 );
148}
149
150
151/// \brief std::tie` like function that ties fields of a structure.
152///
153/// \returns a `std::tuple` with lvalue and const lvalue references to fields of an \aggregate `val`.
154///
155/// \b Example:
156/// \code
157/// void foo(const int&, const short&);
158/// struct my_struct { int i, short s; };
159///
160/// const my_struct const_s{1, 2};
161/// std::apply(foo, boost::pfr::structure_tie(const_s));
162///
163/// my_struct s;
164/// boost::pfr::structure_tie(s) = std::tuple<int, short>{10, 11};
165/// assert(s.s == 11);
166/// \endcode
167template <class T>
168constexpr auto structure_tie(const T& val) noexcept {
169 return detail::make_conststdtiedtuple_from_tietuple(
170 detail::tie_as_tuple(const_cast<T&>(val)),
171 detail::make_index_sequence< tuple_size_v<T> >()
172 );
173}
174
175
176/// \overload structure_tie
177template <class T>
178constexpr auto structure_tie(T& val
179#if !BOOST_PFR_USE_CPP17
180 , std::enable_if_t<std::is_assignable<T, T>::value>* = nullptr
181#endif
182) noexcept {
183 return detail::make_stdtiedtuple_from_tietuple(
184 detail::tie_as_tuple(val),
185 detail::make_index_sequence< tuple_size_v<T> >()
186 );
187}
188
189#if !BOOST_PFR_USE_CPP17
190/// \overload structure_tie
191template <class T>
192constexpr auto structure_tie(T&, std::enable_if_t<!std::is_assignable<T, T>::value>* = nullptr) noexcept {
193 static_assert(sizeof(T) && false, "====================> Boost.PFR: Calling boost::pfr::structure_tie on non const non assignable type is allowed only in C++17");
194 return 0;
195}
196#endif
197
198
199/// \overload structure_tie
200template <class T>
201constexpr auto structure_tie(T&&, std::enable_if_t< std::is_rvalue_reference<T&&>::value>* = nullptr) noexcept {
202 static_assert(sizeof(T) && false, "====================> Boost.PFR: Calling boost::pfr::structure_tie on rvalue references is forbidden");
203 return 0;
204}
205
206/// Calls `func` for each field of a `value`.
207///
208/// \param func must have one of the following signatures:
209/// * any_return_type func(U&& field) // field of value is perfect forwarded to function
210/// * any_return_type func(U&& field, std::size_t i)
211/// * any_return_type func(U&& value, I i) // Here I is an `std::integral_constant<size_t, field_index>`
212///
213/// \param value To each field of this variable will be the `func` applied.
214///
215/// \b Example:
216/// \code
217/// struct my_struct { int i, short s; };
218/// int sum = 0;
219/// boost::pfr::for_each_field(my_struct{20, 22}, [&sum](const auto& field) { sum += field; });
220/// assert(sum == 42);
221/// \endcode
222template <class T, class F>
223constexpr void for_each_field(T&& value, F&& func) {
224 constexpr std::size_t fields_count_val = boost::pfr::detail::fields_count<std::remove_reference_t<T>>();
225
226 ::boost::pfr::detail::for_each_field_dispatcher(
227 value,
228 [f = std::forward<F>(func)](auto&& t) mutable {
229 // MSVC related workaround. Its lambdas do not capture constexprs.
230 constexpr std::size_t fields_count_val_in_lambda
231 = boost::pfr::detail::fields_count<std::remove_reference_t<T>>();
232
233 ::boost::pfr::detail::for_each_field_impl(
234 t,
235 std::forward<F>(f),
236 detail::make_index_sequence<fields_count_val_in_lambda>{},
237 std::is_rvalue_reference<T&&>{}
238 );
239 },
240 detail::make_index_sequence<fields_count_val>{}
241 );
242}
243
244/// \brief std::tie-like function that allows assigning to tied values from aggregates.
245///
246/// \returns an object with lvalue references to `args...`; on assignment of an \aggregate value to that
247/// object each field of an aggregate is assigned to the corresponding `args...` reference.
248///
249/// \b Example:
250/// \code
251/// auto f() {
252/// struct { struct { int x, y } p; short s; } res { { 4, 5 }, 6 };
253/// return res;
254/// }
255/// auto [p, s] = f();
256/// boost::pfr::tie_from_structure(p, s) = f();
257/// \endcode
258template <typename... Elements>
259constexpr detail::tie_from_structure_tuple<Elements...> tie_from_structure(Elements&... args) noexcept {
260 return detail::tie_from_structure_tuple<Elements...>(args...);
261}
262
263}} // namespace boost::pfr
264
265#endif // BOOST_PFR_CORE_HPP
266

source code of boost/libs/pfr/include/boost/pfr/core.hpp