mirror of
https://github.com/boostorg/pfr.git
synced 2026-02-01 08:42:14 +00:00
Compare commits
9 Commits
master
...
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
|
||||
[quickbook 1.6]
|
||||
[version 2.3]
|
||||
[version 2.4]
|
||||
[copyright 2016-2026 Antony Polukhin]
|
||||
[category Language Features Emulation]
|
||||
[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:
|
||||
[table:linkmacro Macros
|
||||
[[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_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.]]
|
||||
@@ -594,11 +595,13 @@ clang++ -std=c++20 -fmodule-file=boost_pfr.pcm boost_pfr.pcm usage_sample.cpp
|
||||
Short description:
|
||||
|
||||
# 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
|
||||
* [*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
|
||||
* [*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: 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
|
||||
@@ -621,6 +624,8 @@ Description of the [*BOOST_PFR_USE_LOOPHOLE == 1] technique by its inventor Alex
|
||||
|
||||
[h2 Field name retrieval]
|
||||
|
||||
If [*BOOST_PFR_USE_CPP26_REFLECTION == 1] then C++26 Reflection is used to get names. Otherwise:
|
||||
|
||||
# at compile-time:
|
||||
* 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>`.
|
||||
|
||||
@@ -61,6 +61,15 @@
|
||||
#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
|
||||
# ifdef __cpp_structured_bindings
|
||||
# define BOOST_PFR_USE_CPP17 1
|
||||
|
||||
@@ -52,7 +52,9 @@ BOOST_PFR_BEGIN_MODULE_EXPORT
|
||||
/// \endcode
|
||||
template <std::size_t I, class T>
|
||||
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;
|
||||
return std::forward_like<const T &>(members...[I]);
|
||||
#else
|
||||
@@ -67,7 +69,9 @@ constexpr decltype(auto) get(T& val
|
||||
, std::enable_if_t<std::is_assignable<T, T>::value>* = nullptr
|
||||
#endif
|
||||
) 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;
|
||||
return std::forward_like<T &>(members...[I]);
|
||||
#else
|
||||
@@ -75,7 +79,7 @@ constexpr decltype(auto) get(T& val
|
||||
#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
|
||||
template <std::size_t I, class T>
|
||||
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
|
||||
template <std::size_t I, class T>
|
||||
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);
|
||||
return std::move(members...[I]);
|
||||
#else
|
||||
@@ -107,14 +113,14 @@ constexpr const U& get(const T& val) noexcept {
|
||||
/// \overload get
|
||||
template <class U, class T>
|
||||
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
|
||||
#endif
|
||||
) noexcept {
|
||||
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
|
||||
template <class U, class T>
|
||||
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
|
||||
template <class T>
|
||||
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
|
||||
#endif
|
||||
) noexcept {
|
||||
@@ -220,7 +226,7 @@ constexpr auto structure_tie(T& val
|
||||
#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
|
||||
template <class T>
|
||||
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
|
||||
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));
|
||||
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
|
||||
|
||||
@@ -13,7 +13,9 @@
|
||||
// `boost::pfr::detail::for_each_field_dispatcher` 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>
|
||||
#elif BOOST_PFR_USE_CPP17
|
||||
# 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
|
||||
// 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>
|
||||
#else
|
||||
#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();
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
|
||||
@@ -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>()>{});
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
#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 <type_traits>
|
||||
#include <utility> // metaprogramming stuff
|
||||
|
||||
#if BOOST_PFR_USE_CPP26_REFLECTION
|
||||
#include <meta>
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#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 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
|
||||
constexpr std::size_t fields_count_compiler_limitation_next(std::size_t n) noexcept {
|
||||
#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>);
|
||||
}
|
||||
|
||||
#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>
|
||||
constexpr auto fields_count_dispatch_impl(const T &t) noexcept
|
||||
{
|
||||
|
||||
@@ -28,6 +28,11 @@ import std;
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <variant>
|
||||
|
||||
#ifdef __cpp_lib_reflection
|
||||
#include <meta>
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#define BOOST_PFR_INTERFACE_UNIT
|
||||
|
||||
@@ -15,6 +15,7 @@ int main() {
|
||||
std::cout << "Platform info:" << '\n'
|
||||
<< "BOOST_PFR_USE_CPP17 == " << BOOST_PFR_USE_CPP17 << '\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_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'
|
||||
|
||||
@@ -45,6 +45,9 @@ explicit compiler_supports_loophole ;
|
||||
mp-run-simple variadic_structured_binding_detection.cpp : : : : 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
|
||||
|
||||
|
||||
@@ -55,11 +58,15 @@ local REQUIRE_LOOPHOLE =
|
||||
local REQUIRE_VSB =
|
||||
[ 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 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 LOOPHOLE_ENGINE = <define>BOOST_PFR_USE_LOOPHOLE=1 <define>BOOST_PFR_USE_CPP17=0 <define>BOOST_PFR_USE_CPP26=0 $(REQUIRE_LOOPHOLE) ;
|
||||
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 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 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 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 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
|
||||
:
|
||||
@@ -116,6 +123,7 @@ local BLACKLIST_TESTS_FOR_CLASSIC =
|
||||
for local source_file in [ glob ./run/*.cpp ] [ glob ../../example/*.cpp ]
|
||||
{
|
||||
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) : : : $(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