mirror of
https://github.com/boostorg/pfr.git
synced 2026-02-01 08:42:14 +00:00
Compare commits
9 Commits
develop
...
reflection
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f3324ed1c1 | ||
|
|
b12551c547 | ||
|
|
b7f8dfe109 | ||
|
|
25b5fd744d | ||
|
|
56c12f35d5 | ||
|
|
c698cb4009 | ||
|
|
bad6129b56 | ||
|
|
08a78e7471 | ||
|
|
114ef61060 |
13
doc/pfr.qbk
13
doc/pfr.qbk
@@ -1,6 +1,6 @@
|
|||||||
[library Boost.PFR
|
[library Boost.PFR
|
||||||
[quickbook 1.6]
|
[quickbook 1.6]
|
||||||
[version 2.3]
|
[version 2.4]
|
||||||
[copyright 2016-2026 Antony Polukhin]
|
[copyright 2016-2026 Antony Polukhin]
|
||||||
[category Language Features Emulation]
|
[category Language Features Emulation]
|
||||||
[license
|
[license
|
||||||
@@ -501,6 +501,7 @@ Boost.PFRs extraction of field name works with only `SimpleAggregate` types.
|
|||||||
By default Boost.PFR [*auto-detects your compiler abilities] and automatically defines the configuration macro into appropriate values. If you wish to override that behavior, just define:
|
By default Boost.PFR [*auto-detects your compiler abilities] and automatically defines the configuration macro into appropriate values. If you wish to override that behavior, just define:
|
||||||
[table:linkmacro Macros
|
[table:linkmacro Macros
|
||||||
[[Macro name] [Effect]]
|
[[Macro name] [Effect]]
|
||||||
|
[[*BOOST_PFR_USE_CPP26_REFLECTION*] [Define to `1` if you wish to override Boost.PFR choice and use C++26 Reflection. Define to `0` to override Boost.PFR choice and disable C++26 Reflection usage.]]
|
||||||
[[*BOOST_PFR_USE_CPP26*] [Define to `1` if you wish to override Boost.PFR choice and use C++26 variadic structured bindings for reflection. Define to `0` to override Boost.PFR choice and disable C++26 variadic structured bindings usage.]]
|
[[*BOOST_PFR_USE_CPP26*] [Define to `1` if you wish to override Boost.PFR choice and use C++26 variadic structured bindings for reflection. Define to `0` to override Boost.PFR choice and disable C++26 variadic structured bindings usage.]]
|
||||||
[[*BOOST_PFR_USE_CPP17*] [Define to `1` if you wish to override Boost.PFR choice and use C++17 structured bindings for reflection. Define to `0` to override Boost.PFR choice and disable C++17 structured bindings usage.]]
|
[[*BOOST_PFR_USE_CPP17*] [Define to `1` if you wish to override Boost.PFR choice and use C++17 structured bindings for reflection. Define to `0` to override Boost.PFR choice and disable C++17 structured bindings usage.]]
|
||||||
[[*BOOST_PFR_USE_LOOPHOLE*] [Define to `1` if you wish to override Boost.PFR choice and exploit [@http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2118 CWG 2118] for reflection. Define to `0` to override Boost.PFR choice and disable CWG 2118 usage.]]
|
[[*BOOST_PFR_USE_LOOPHOLE*] [Define to `1` if you wish to override Boost.PFR choice and exploit [@http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2118 CWG 2118] for reflection. Define to `0` to override Boost.PFR choice and disable CWG 2118 usage.]]
|
||||||
@@ -594,11 +595,13 @@ clang++ -std=c++20 -fmodule-file=boost_pfr.pcm boost_pfr.pcm usage_sample.cpp
|
|||||||
Short description:
|
Short description:
|
||||||
|
|
||||||
# at compile-time: use aggregate initialization to detect fields count in user-provided structure
|
# at compile-time: use aggregate initialization to detect fields count in user-provided structure
|
||||||
* [*BOOST_PFR_USE_CPP26 == 1]:
|
* [*BOOST_PFR_USE_CPP26_REFLECTION == 1]:
|
||||||
|
# at compile-time: C++26 Reflection is used to make reference to field
|
||||||
|
* [*BOOST_PFR_USE_CPP26_REFLECTION == 0 && BOOST_PFR_USE_CPP26 == 1]:
|
||||||
# at compile-time: structured bindings are used to decompose a type `T` to known variadic amount of fields
|
# at compile-time: structured bindings are used to decompose a type `T` to known variadic amount of fields
|
||||||
* [*BOOST_PFR_USE_CPP26 == 0 && BOOST_PFR_USE_CPP17 == 1]:
|
* [*BOOST_PFR_USE_CPP26_REFLECTION == 0 && BOOST_PFR_USE_CPP26 == 0 && BOOST_PFR_USE_CPP17 == 1]:
|
||||||
# at compile-time: structured bindings are used to decompose a type `T` to known amount of fields
|
# at compile-time: structured bindings are used to decompose a type `T` to known amount of fields
|
||||||
* [*BOOST_PFR_USE_CPP26 == 0 && BOOST_PFR_USE_CPP17 == 0 && BOOST_PFR_USE_LOOPHOLE == 1]:
|
* [*BOOST_PFR_USE_CPP26_REFLECTION == 0 && BOOST_PFR_USE_CPP26 == 0 && BOOST_PFR_USE_CPP17 == 0 && BOOST_PFR_USE_LOOPHOLE == 1]:
|
||||||
# at compile-time: use aggregate initialization to detect fields count in user-provided structure
|
# at compile-time: use aggregate initialization to detect fields count in user-provided structure
|
||||||
# at compile-time: make a structure that is convertible to anything and remember types it has been converted to during aggregate initialization of user-provided structure
|
# at compile-time: make a structure that is convertible to anything and remember types it has been converted to during aggregate initialization of user-provided structure
|
||||||
# at compile-time: using knowledge from previous steps create a tuple with exactly the same layout as in user-provided structure
|
# at compile-time: using knowledge from previous steps create a tuple with exactly the same layout as in user-provided structure
|
||||||
@@ -621,6 +624,8 @@ Description of the [*BOOST_PFR_USE_LOOPHOLE == 1] technique by its inventor Alex
|
|||||||
|
|
||||||
[h2 Field name retrieval]
|
[h2 Field name retrieval]
|
||||||
|
|
||||||
|
If [*BOOST_PFR_USE_CPP26_REFLECTION == 1] then C++26 Reflection is used to get names. Otherwise:
|
||||||
|
|
||||||
# at compile-time:
|
# at compile-time:
|
||||||
* Get references to members of an object of type `T` in `constexpr` function
|
* Get references to members of an object of type `T` in `constexpr` function
|
||||||
* Feed the reference from previous as a template parameter to a `constexpr` function with `template <auto member_ptr>`.
|
* Feed the reference from previous as a template parameter to a `constexpr` function with `template <auto member_ptr>`.
|
||||||
|
|||||||
@@ -61,6 +61,15 @@
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef BOOST_PFR_USE_CPP26_REFLECTION
|
||||||
|
#ifdef __cpp_lib_reflection
|
||||||
|
// TODO: experimental. Not enabled by default for now
|
||||||
|
#define BOOST_PFR_USE_CPP26_REFLECTION 0
|
||||||
|
#else
|
||||||
|
#define BOOST_PFR_USE_CPP26_REFLECTION 0
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef BOOST_PFR_USE_CPP17
|
#ifndef BOOST_PFR_USE_CPP17
|
||||||
# ifdef __cpp_structured_bindings
|
# ifdef __cpp_structured_bindings
|
||||||
# define BOOST_PFR_USE_CPP17 1
|
# define BOOST_PFR_USE_CPP17 1
|
||||||
|
|||||||
@@ -52,7 +52,9 @@ BOOST_PFR_BEGIN_MODULE_EXPORT
|
|||||||
/// \endcode
|
/// \endcode
|
||||||
template <std::size_t I, class T>
|
template <std::size_t I, class T>
|
||||||
constexpr decltype(auto) get(const T& val) noexcept {
|
constexpr decltype(auto) get(const T& val) noexcept {
|
||||||
#if BOOST_PFR_USE_CPP26
|
#if BOOST_PFR_USE_CPP26_REFLECTION
|
||||||
|
return detail::reference_by_index<I>(val);
|
||||||
|
#elif BOOST_PFR_USE_CPP26
|
||||||
const auto& [... members] = val;
|
const auto& [... members] = val;
|
||||||
return std::forward_like<const T &>(members...[I]);
|
return std::forward_like<const T &>(members...[I]);
|
||||||
#else
|
#else
|
||||||
@@ -67,7 +69,9 @@ constexpr decltype(auto) get(T& val
|
|||||||
, std::enable_if_t<std::is_assignable<T, T>::value>* = nullptr
|
, std::enable_if_t<std::is_assignable<T, T>::value>* = nullptr
|
||||||
#endif
|
#endif
|
||||||
) noexcept {
|
) noexcept {
|
||||||
#if BOOST_PFR_USE_CPP26
|
#if BOOST_PFR_USE_CPP26_REFLECTION
|
||||||
|
return detail::reference_by_index<I>(val);
|
||||||
|
#elif BOOST_PFR_USE_CPP26
|
||||||
auto& [... members] = val;
|
auto& [... members] = val;
|
||||||
return std::forward_like<T &>(members...[I]);
|
return std::forward_like<T &>(members...[I]);
|
||||||
#else
|
#else
|
||||||
@@ -75,7 +79,7 @@ constexpr decltype(auto) get(T& val
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !BOOST_PFR_USE_CPP17 && !BOOST_PFR_USE_CPP26
|
#if !BOOST_PFR_USE_CPP17 && !BOOST_PFR_USE_CPP26 && !BOOST_PFR_USE_CPP26_REFLECTION
|
||||||
/// \overload get
|
/// \overload get
|
||||||
template <std::size_t I, class T>
|
template <std::size_t I, class T>
|
||||||
constexpr auto get(T&, std::enable_if_t<!std::is_assignable<T, T>::value>* = nullptr) noexcept {
|
constexpr auto get(T&, std::enable_if_t<!std::is_assignable<T, T>::value>* = nullptr) noexcept {
|
||||||
@@ -88,7 +92,9 @@ constexpr auto get(T&, std::enable_if_t<!std::is_assignable<T, T>::value>* = nul
|
|||||||
/// \overload get
|
/// \overload get
|
||||||
template <std::size_t I, class T>
|
template <std::size_t I, class T>
|
||||||
constexpr auto get(T&& val, std::enable_if_t< std::is_rvalue_reference<T&&>::value>* = nullptr) noexcept {
|
constexpr auto get(T&& val, std::enable_if_t< std::is_rvalue_reference<T&&>::value>* = nullptr) noexcept {
|
||||||
#if BOOST_PFR_USE_CPP26
|
#if BOOST_PFR_USE_CPP26_REFLECTION
|
||||||
|
return std::move(detail::reference_by_index<I>(val));
|
||||||
|
#elif BOOST_PFR_USE_CPP26
|
||||||
auto&& [... members] = std::forward<T>(val);
|
auto&& [... members] = std::forward<T>(val);
|
||||||
return std::move(members...[I]);
|
return std::move(members...[I]);
|
||||||
#else
|
#else
|
||||||
@@ -107,14 +113,14 @@ constexpr const U& get(const T& val) noexcept {
|
|||||||
/// \overload get
|
/// \overload get
|
||||||
template <class U, class T>
|
template <class U, class T>
|
||||||
constexpr U& get(T& val
|
constexpr U& get(T& val
|
||||||
#if !BOOST_PFR_USE_CPP17 && !BOOST_PFR_USE_CPP26
|
#if !BOOST_PFR_USE_CPP17 && !BOOST_PFR_USE_CPP26 && !BOOST_PFR_USE_CPP26_REFLECTION
|
||||||
, std::enable_if_t<std::is_assignable<T, T>::value>* = nullptr
|
, std::enable_if_t<std::is_assignable<T, T>::value>* = nullptr
|
||||||
#endif
|
#endif
|
||||||
) noexcept {
|
) noexcept {
|
||||||
return detail::sequence_tuple::get_by_type_impl<U&>( detail::tie_as_tuple(val) );
|
return detail::sequence_tuple::get_by_type_impl<U&>( detail::tie_as_tuple(val) );
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !BOOST_PFR_USE_CPP17 && !BOOST_PFR_USE_CPP26
|
#if !BOOST_PFR_USE_CPP17 && !BOOST_PFR_USE_CPP26 && !BOOST_PFR_USE_CPP26_REFLECTION
|
||||||
/// \overload get
|
/// \overload get
|
||||||
template <class U, class T>
|
template <class U, class T>
|
||||||
constexpr U& get(T&, std::enable_if_t<!std::is_assignable<T, T>::value>* = nullptr) noexcept {
|
constexpr U& get(T&, std::enable_if_t<!std::is_assignable<T, T>::value>* = nullptr) noexcept {
|
||||||
@@ -207,7 +213,7 @@ constexpr auto structure_tie(const T& val) noexcept {
|
|||||||
/// \overload structure_tie
|
/// \overload structure_tie
|
||||||
template <class T>
|
template <class T>
|
||||||
constexpr auto structure_tie(T& val
|
constexpr auto structure_tie(T& val
|
||||||
#if !BOOST_PFR_USE_CPP17 && !BOOST_PFR_USE_CPP26
|
#if !BOOST_PFR_USE_CPP17 && !BOOST_PFR_USE_CPP26 && !BOOST_PFR_USE_CPP26_REFLECTION
|
||||||
, std::enable_if_t<std::is_assignable<T, T>::value>* = nullptr
|
, std::enable_if_t<std::is_assignable<T, T>::value>* = nullptr
|
||||||
#endif
|
#endif
|
||||||
) noexcept {
|
) noexcept {
|
||||||
@@ -220,7 +226,7 @@ constexpr auto structure_tie(T& val
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !BOOST_PFR_USE_CPP17 && !BOOST_PFR_USE_CPP26
|
#if !BOOST_PFR_USE_CPP17 && !BOOST_PFR_USE_CPP26 && !BOOST_PFR_USE_CPP26_REFLECTION
|
||||||
/// \overload structure_tie
|
/// \overload structure_tie
|
||||||
template <class T>
|
template <class T>
|
||||||
constexpr auto structure_tie(T&, std::enable_if_t<!std::is_assignable<T, T>::value>* = nullptr) noexcept {
|
constexpr auto structure_tie(T&, std::enable_if_t<!std::is_assignable<T, T>::value>* = nullptr) noexcept {
|
||||||
|
|||||||
@@ -106,7 +106,18 @@ names_as_array() noexcept {
|
|||||||
/// \endcode
|
/// \endcode
|
||||||
template <class T, class F>
|
template <class T, class F>
|
||||||
constexpr void for_each_field_with_name(T&& value, F&& func) {
|
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));
|
return boost::pfr::detail::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));
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_PFR_END_MODULE_EXPORT
|
BOOST_PFR_END_MODULE_EXPORT
|
||||||
|
|||||||
@@ -13,7 +13,9 @@
|
|||||||
// `boost::pfr::detail::for_each_field_dispatcher` functions.
|
// `boost::pfr::detail::for_each_field_dispatcher` functions.
|
||||||
//
|
//
|
||||||
// The whole PFR library is build on top of those two functions.
|
// The whole PFR library is build on top of those two functions.
|
||||||
#if BOOST_PFR_USE_CPP26
|
#if BOOST_PFR_USE_CPP26_REFLECTION
|
||||||
|
#include <boost/pfr/detail/core26_reflection.hpp>
|
||||||
|
#elif BOOST_PFR_USE_CPP26
|
||||||
#include <boost/pfr/detail/core26.hpp>
|
#include <boost/pfr/detail/core26.hpp>
|
||||||
#elif BOOST_PFR_USE_CPP17
|
#elif BOOST_PFR_USE_CPP17
|
||||||
# include <boost/pfr/detail/core17.hpp>
|
# include <boost/pfr/detail/core17.hpp>
|
||||||
|
|||||||
64
include/boost/pfr/detail/core26_reflection.hpp
Normal file
64
include/boost/pfr/detail/core26_reflection.hpp
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
// Copyright (c) 2025-2026 Antony Polukhin
|
||||||
|
//
|
||||||
|
// 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)
|
||||||
|
|
||||||
|
#ifndef BOOST_PFR_DETAIL_CORE26_REFLECTION_HPP
|
||||||
|
#define BOOST_PFR_DETAIL_CORE26_REFLECTION_HPP
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <boost/pfr/detail/config.hpp>
|
||||||
|
#include <boost/pfr/detail/fields_count.hpp>
|
||||||
|
#include <boost/pfr/detail/make_integer_sequence.hpp>
|
||||||
|
#include <boost/pfr/detail/sequence_tuple.hpp>
|
||||||
|
|
||||||
|
#if !defined(BOOST_PFR_INTERFACE_UNIT)
|
||||||
|
#include <type_traits>
|
||||||
|
#include <meta>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace boost::pfr::detail {
|
||||||
|
|
||||||
|
template <std::size_t I, typename T>
|
||||||
|
consteval decltype(auto) reference_by_index(T &val) noexcept {
|
||||||
|
return val.[:
|
||||||
|
nonstatic_data_members_of(
|
||||||
|
^^T,
|
||||||
|
std::meta::access_context::current()
|
||||||
|
).at(I)
|
||||||
|
:];
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T, std::size_t... I>
|
||||||
|
constexpr auto tie_as_tuple_impl(T &val, std::index_sequence<I...>) noexcept {
|
||||||
|
return sequence_tuple::tuple<
|
||||||
|
decltype(boost::pfr::detail::reference_by_index<I>(val))...
|
||||||
|
>{
|
||||||
|
boost::pfr::detail::reference_by_index<I>(val)...
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
constexpr auto tie_as_tuple(T &val) noexcept {
|
||||||
|
return detail::tie_as_tuple_impl(
|
||||||
|
val,
|
||||||
|
detail::make_index_sequence<detail::fields_count<T>()>{}
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T, class F, std::size_t... I>
|
||||||
|
constexpr void for_each_field_dispatcher(T& t, F&& f, std::index_sequence<I...>) {
|
||||||
|
static_assert(
|
||||||
|
!std::is_union<T>::value,
|
||||||
|
"====================> Boost.PFR: For safety reasons it is forbidden to reflect unions. See `Reflection of unions` section in the docs for more info."
|
||||||
|
);
|
||||||
|
std::forward<F>(f)(
|
||||||
|
detail::tie_as_tuple(t)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace boost::pfr::detail
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -19,7 +19,9 @@
|
|||||||
//
|
//
|
||||||
// The whole functional of extracting field's names is build on top of those
|
// The whole functional of extracting field's names is build on top of those
|
||||||
// two functions.
|
// two functions.
|
||||||
#if BOOST_PFR_CORE_NAME_ENABLED
|
#if BOOST_PFR_USE_CPP26_REFLECTION
|
||||||
|
#include <boost/pfr/detail/core_name26_reflection.hpp>
|
||||||
|
#elif BOOST_PFR_CORE_NAME_ENABLED
|
||||||
#include <boost/pfr/detail/core_name20_static.hpp>
|
#include <boost/pfr/detail/core_name20_static.hpp>
|
||||||
#else
|
#else
|
||||||
#include <boost/pfr/detail/core_name14_disabled.hpp>
|
#include <boost/pfr/detail/core_name14_disabled.hpp>
|
||||||
|
|||||||
@@ -37,15 +37,6 @@ constexpr auto tie_as_names_tuple() noexcept {
|
|||||||
return detail::sequence_tuple::make_sequence_tuple();
|
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
|
}}} // namespace boost::pfr::detail
|
||||||
|
|
||||||
#endif // BOOST_PFR_DETAIL_CORE_NAME14_DISABLED_HPP
|
#endif // BOOST_PFR_DETAIL_CORE_NAME14_DISABLED_HPP
|
||||||
|
|||||||
@@ -241,22 +241,6 @@ constexpr auto tie_as_names_tuple() noexcept {
|
|||||||
return detail::tie_as_names_tuple_impl<T>(detail::make_index_sequence<detail::fields_count<T>()>{});
|
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::detail::for_each_field(
|
|
||||||
std::forward<T>(value),
|
|
||||||
[&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>) {
|
|
||||||
std::forward<F>(func)(name, std::forward<FieldType>(field), index);
|
|
||||||
} else {
|
|
||||||
std::forward<F>(func)(name, std::forward<FieldType>(field));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
}}} // namespace boost::pfr::detail
|
}}} // namespace boost::pfr::detail
|
||||||
|
|
||||||
#endif // BOOST_PFR_DETAIL_CORE_NAME20_STATIC_HPP
|
#endif // BOOST_PFR_DETAIL_CORE_NAME20_STATIC_HPP
|
||||||
|
|||||||
63
include/boost/pfr/detail/core_name26_reflection.hpp
Normal file
63
include/boost/pfr/detail/core_name26_reflection.hpp
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
// Copyright (c) 2016-2026 Antony Polukhin
|
||||||
|
//
|
||||||
|
// 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)
|
||||||
|
|
||||||
|
|
||||||
|
// Initial implementation by Bela Schaum, https://github.com/schaumb
|
||||||
|
// The way to make it union and UB free by X-Ryl669, https://github.com/X-Ryl669
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef BOOST_PFR_DETAIL_CORE_NAME26_REFLECTION_HPP
|
||||||
|
#define BOOST_PFR_DETAIL_CORE_NAME26_REFLECTION_HPP
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <boost/pfr/detail/config.hpp>
|
||||||
|
|
||||||
|
#include <boost/pfr/detail/fields_count.hpp>
|
||||||
|
#include <boost/pfr/detail/for_each_field.hpp>
|
||||||
|
#include <boost/pfr/detail/make_integer_sequence.hpp>
|
||||||
|
#include <boost/pfr/detail/sequence_tuple.hpp>
|
||||||
|
|
||||||
|
#if !defined(BOOST_PFR_INTERFACE_UNIT)
|
||||||
|
#include <type_traits>
|
||||||
|
#include <array>
|
||||||
|
#include <memory> // for std::addressof
|
||||||
|
#include <meta>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace boost { namespace pfr { namespace detail {
|
||||||
|
|
||||||
|
template <class T, std::size_t I>
|
||||||
|
constexpr std::string_view get_name() noexcept {
|
||||||
|
static_assert(
|
||||||
|
!std::is_union<T>::value,
|
||||||
|
"====================> Boost.PFR: For safety reasons it is forbidden to reflect unions. See `Reflection of unions` section in the docs for more info."
|
||||||
|
);
|
||||||
|
static_assert(
|
||||||
|
!std::is_array<T>::value,
|
||||||
|
"====================> Boost.PFR: It is impossible to extract name from old C array since it doesn't have named members"
|
||||||
|
);
|
||||||
|
|
||||||
|
return identifier_of(
|
||||||
|
nonstatic_data_members_of(
|
||||||
|
^^T,
|
||||||
|
std::meta::access_context::current()
|
||||||
|
).at(I)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T, std::size_t... I>
|
||||||
|
constexpr auto tie_as_names_tuple_impl(std::index_sequence<I...>) noexcept {
|
||||||
|
return detail::sequence_tuple::make_sequence_tuple(detail::get_name<T, I>()...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
constexpr auto tie_as_names_tuple() noexcept {
|
||||||
|
return detail::tie_as_names_tuple_impl<T>(detail::make_index_sequence<detail::fields_count<T>()>{});
|
||||||
|
}
|
||||||
|
|
||||||
|
}}} // namespace boost::pfr::detail
|
||||||
|
|
||||||
|
#endif // BOOST_PFR_DETAIL_CORE_NAME20_STATIC_HPP
|
||||||
|
|
||||||
@@ -16,6 +16,11 @@
|
|||||||
#include <limits>
|
#include <limits>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <utility> // metaprogramming stuff
|
#include <utility> // metaprogramming stuff
|
||||||
|
|
||||||
|
#if BOOST_PFR_USE_CPP26_REFLECTION
|
||||||
|
#include <meta>
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __clang__
|
#ifdef __clang__
|
||||||
@@ -207,7 +212,7 @@ using is_one_element_range = std::integral_constant<bool, Begin == Last>;
|
|||||||
using multi_element_range = std::false_type;
|
using multi_element_range = std::false_type;
|
||||||
using one_element_range = std::true_type;
|
using one_element_range = std::true_type;
|
||||||
|
|
||||||
#if !BOOST_PFR_USE_CPP26
|
#if !BOOST_PFR_USE_CPP26 && !BOOST_PFR_USE_CPP26_REFLECTION
|
||||||
///////////////////// Fields count next expected compiler limitation
|
///////////////////// Fields count next expected compiler limitation
|
||||||
constexpr std::size_t fields_count_compiler_limitation_next(std::size_t n) noexcept {
|
constexpr std::size_t fields_count_compiler_limitation_next(std::size_t n) noexcept {
|
||||||
#if defined(_MSC_VER) && (_MSC_VER <= 1920)
|
#if defined(_MSC_VER) && (_MSC_VER <= 1920)
|
||||||
@@ -344,7 +349,31 @@ constexpr auto fields_count_dispatch(long, long, std::true_type /*are_preconditi
|
|||||||
return sizeof(T) / sizeof(std::remove_all_extents_t<T>);
|
return sizeof(T) / sizeof(std::remove_all_extents_t<T>);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if BOOST_PFR_USE_CPP26
|
#if BOOST_PFR_USE_CPP26_REFLECTION
|
||||||
|
template<class T>
|
||||||
|
constexpr auto fields_count_dispatch_impl(const T &) noexcept
|
||||||
|
{
|
||||||
|
return std::integral_constant<std::size_t,
|
||||||
|
nonstatic_data_members_of(
|
||||||
|
^^T,
|
||||||
|
std::meta::access_context::current()
|
||||||
|
).size()
|
||||||
|
>{};
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
constexpr auto fields_count_dispatch(long, int, std::true_type /*are_preconditions_met*/) noexcept
|
||||||
|
-> std::enable_if_t<std::is_scalar<T>::value, std::size_t>
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
constexpr auto fields_count_dispatch(int, int, std::true_type /*are_preconditions_met*/) noexcept
|
||||||
|
{
|
||||||
|
return decltype(detail::fields_count_dispatch_impl(std::declval<const T &>()))::value;
|
||||||
|
}
|
||||||
|
#elif BOOST_PFR_USE_CPP26
|
||||||
template<class T>
|
template<class T>
|
||||||
constexpr auto fields_count_dispatch_impl(const T &t) noexcept
|
constexpr auto fields_count_dispatch_impl(const T &t) noexcept
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -28,6 +28,11 @@ import std;
|
|||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <variant>
|
#include <variant>
|
||||||
|
|
||||||
|
#ifdef __cpp_lib_reflection
|
||||||
|
#include <meta>
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define BOOST_PFR_INTERFACE_UNIT
|
#define BOOST_PFR_INTERFACE_UNIT
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ int main() {
|
|||||||
std::cout << "Platform info:" << '\n'
|
std::cout << "Platform info:" << '\n'
|
||||||
<< "BOOST_PFR_USE_CPP17 == " << BOOST_PFR_USE_CPP17 << '\n'
|
<< "BOOST_PFR_USE_CPP17 == " << BOOST_PFR_USE_CPP17 << '\n'
|
||||||
<< "BOOST_PFR_USE_CPP26 == " << BOOST_PFR_USE_CPP26 << '\n'
|
<< "BOOST_PFR_USE_CPP26 == " << BOOST_PFR_USE_CPP26 << '\n'
|
||||||
|
<< "BOOST_PFR_USE_CPP26_REFLECTION == " << BOOST_PFR_USE_CPP26_REFLECTION << '\n'
|
||||||
<< "BOOST_PFR_USE_LOOPHOLE == " << BOOST_PFR_USE_LOOPHOLE << '\n'
|
<< "BOOST_PFR_USE_LOOPHOLE == " << BOOST_PFR_USE_LOOPHOLE << '\n'
|
||||||
<< "BOOST_PFR_USE_STD_MAKE_INTEGRAL_SEQUENCE == " << BOOST_PFR_USE_STD_MAKE_INTEGRAL_SEQUENCE << '\n'
|
<< "BOOST_PFR_USE_STD_MAKE_INTEGRAL_SEQUENCE == " << BOOST_PFR_USE_STD_MAKE_INTEGRAL_SEQUENCE << '\n'
|
||||||
<< "BOOST_PFR_HAS_GUARANTEED_COPY_ELISION == " << BOOST_PFR_HAS_GUARANTEED_COPY_ELISION << '\n'
|
<< "BOOST_PFR_HAS_GUARANTEED_COPY_ELISION == " << BOOST_PFR_HAS_GUARANTEED_COPY_ELISION << '\n'
|
||||||
|
|||||||
@@ -45,6 +45,9 @@ explicit compiler_supports_loophole ;
|
|||||||
mp-run-simple variadic_structured_binding_detection.cpp : : : : compiler_supports_vsb ;
|
mp-run-simple variadic_structured_binding_detection.cpp : : : : compiler_supports_vsb ;
|
||||||
explicit compiler_supports_vsb ;
|
explicit compiler_supports_vsb ;
|
||||||
|
|
||||||
|
mp-run-simple cpp26_reflection_detection.cpp : : : : compiler_supports_cpp26_reflection ;
|
||||||
|
explicit compiler_supports_cpp26_reflection ;
|
||||||
|
|
||||||
########## END of helpers to detect Loophole trick support
|
########## END of helpers to detect Loophole trick support
|
||||||
|
|
||||||
|
|
||||||
@@ -55,11 +58,15 @@ local REQUIRE_LOOPHOLE =
|
|||||||
local REQUIRE_VSB =
|
local REQUIRE_VSB =
|
||||||
[ check-target-builds ../core//compiler_supports_vsb : : <build>no ]
|
[ check-target-builds ../core//compiler_supports_vsb : : <build>no ]
|
||||||
;
|
;
|
||||||
|
local REQUIRE_CPP26_REFLECTION =
|
||||||
|
[ check-target-builds ../core//compiler_supports_cpp26_reflection : : <build>no ]
|
||||||
|
;
|
||||||
|
|
||||||
local VARIADIC_STRUCTURED_BINDING_ENGINE = <define>BOOST_PFR_USE_LOOPHOLE=0 <define>BOOST_PFR_USE_CPP17=0 <define>BOOST_PFR_USE_CPP26=1 $(REQUIRE_VSB) ;
|
local CPP26_REFLECTION_ENGINE = <define>BOOST_PFR_USE_LOOPHOLE=0 <define>BOOST_PFR_USE_CPP17=0 <define>BOOST_PFR_USE_CPP26=0 <define>BOOST_PFR_USE_CPP26_REFLECTION=1 $(REQUIRE_CPP26_REFLECTION) ;
|
||||||
local STRUCTURED_BINDING_ENGINE = <define>BOOST_PFR_USE_LOOPHOLE=0 <define>BOOST_PFR_USE_CPP17=1 <define>BOOST_PFR_USE_CPP26=0 [ requires cxx17_structured_bindings ] ;
|
local VARIADIC_STRUCTURED_BINDING_ENGINE = <define>BOOST_PFR_USE_LOOPHOLE=0 <define>BOOST_PFR_USE_CPP17=0 <define>BOOST_PFR_USE_CPP26=1 <define>BOOST_PFR_USE_CPP26_REFLECTION=0 $(REQUIRE_VSB) ;
|
||||||
local LOOPHOLE_ENGINE = <define>BOOST_PFR_USE_LOOPHOLE=1 <define>BOOST_PFR_USE_CPP17=0 <define>BOOST_PFR_USE_CPP26=0 $(REQUIRE_LOOPHOLE) ;
|
local STRUCTURED_BINDING_ENGINE = <define>BOOST_PFR_USE_LOOPHOLE=0 <define>BOOST_PFR_USE_CPP17=1 <define>BOOST_PFR_USE_CPP26=0 <define>BOOST_PFR_USE_CPP26_REFLECTION=0 [ requires cxx17_structured_bindings ] ;
|
||||||
local CLASSIC_ENGINE = <define>BOOST_PFR_USE_LOOPHOLE=0 <define>BOOST_PFR_USE_CPP17=0 <define>BOOST_PFR_USE_CPP26=0 $(DISABLE_ON_MSVC) ;
|
local LOOPHOLE_ENGINE = <define>BOOST_PFR_USE_LOOPHOLE=1 <define>BOOST_PFR_USE_CPP17=0 <define>BOOST_PFR_USE_CPP26=0 <define>BOOST_PFR_USE_CPP26_REFLECTION=0 $(REQUIRE_LOOPHOLE) ;
|
||||||
|
local CLASSIC_ENGINE = <define>BOOST_PFR_USE_LOOPHOLE=0 <define>BOOST_PFR_USE_CPP17=0 <define>BOOST_PFR_USE_CPP26=0 <define>BOOST_PFR_USE_CPP26_REFLECTION=0 $(DISABLE_ON_MSVC) ;
|
||||||
|
|
||||||
test-suite pfr_tests
|
test-suite pfr_tests
|
||||||
:
|
:
|
||||||
@@ -116,6 +123,7 @@ local BLACKLIST_TESTS_FOR_CLASSIC =
|
|||||||
for local source_file in [ glob ./run/*.cpp ] [ glob ../../example/*.cpp ]
|
for local source_file in [ glob ./run/*.cpp ] [ glob ../../example/*.cpp ]
|
||||||
{
|
{
|
||||||
local target_name = $(source_file[1]:B) ;
|
local target_name = $(source_file[1]:B) ;
|
||||||
|
pfr_tests += [ run $(source_file) : : : $(CPP26_REFLECTION_ENGINE) : $(target_name)_refl ] ;
|
||||||
pfr_tests += [ run $(source_file) : : : $(VARIADIC_STRUCTURED_BINDING_ENGINE) : $(target_name)_vsb ] ;
|
pfr_tests += [ run $(source_file) : : : $(VARIADIC_STRUCTURED_BINDING_ENGINE) : $(target_name)_vsb ] ;
|
||||||
pfr_tests += [ run $(source_file) : : : $(STRUCTURED_BINDING_ENGINE) : $(target_name)_sb ] ;
|
pfr_tests += [ run $(source_file) : : : $(STRUCTURED_BINDING_ENGINE) : $(target_name)_sb ] ;
|
||||||
|
|
||||||
|
|||||||
35
test/core/cpp26_reflection_detection.cpp
Normal file
35
test/core/cpp26_reflection_detection.cpp
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
// Copyright (c) 2025-2026 Antony Polukhin
|
||||||
|
//
|
||||||
|
// 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)
|
||||||
|
|
||||||
|
// Detection of C++26 Reflection
|
||||||
|
|
||||||
|
#include <type_traits>
|
||||||
|
#include <version>
|
||||||
|
|
||||||
|
#ifndef __cpp_lib_reflection
|
||||||
|
#error Compiler does not support the required features
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <meta>
|
||||||
|
|
||||||
|
struct MyPair {
|
||||||
|
int first;
|
||||||
|
int second;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
auto test() {
|
||||||
|
return T{}.[:
|
||||||
|
nonstatic_data_members_of(
|
||||||
|
^^T,
|
||||||
|
std::meta::access_context::current()
|
||||||
|
).at(0)
|
||||||
|
:];
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
return ::test<MyPair>();
|
||||||
|
}
|
||||||
|
|
||||||
Reference in New Issue
Block a user