mirror of
https://github.com/boostorg/pfr.git
synced 2026-01-19 16:32:13 +00:00
Multiple fixes for the structured bindings pack implementation (#221)
This commit is contained in:
@@ -53,7 +53,7 @@ BOOST_PFR_BEGIN_MODULE_EXPORT
|
||||
template <std::size_t I, class T>
|
||||
constexpr decltype(auto) get(const T& val) noexcept {
|
||||
#if BOOST_PFR_USE_CPP26
|
||||
const auto &[... members] = val;
|
||||
const auto& [... members] = val;
|
||||
return std::forward_like<const T &>(members...[I]);
|
||||
#else
|
||||
return detail::sequence_tuple::get<I>(detail::tie_as_tuple(val));
|
||||
@@ -63,23 +63,23 @@ constexpr decltype(auto) get(const T& val) noexcept {
|
||||
/// \overload get
|
||||
template <std::size_t I, class T>
|
||||
constexpr decltype(auto) get(T& val
|
||||
#if !BOOST_PFR_USE_CPP17
|
||||
#if !BOOST_PFR_USE_CPP17 && !BOOST_PFR_USE_CPP26
|
||||
, std::enable_if_t<std::is_assignable<T, T>::value>* = nullptr
|
||||
#endif
|
||||
) noexcept {
|
||||
#if BOOST_PFR_USE_CPP26
|
||||
auto &[... members] = val;
|
||||
auto& [... members] = val;
|
||||
return std::forward_like<T &>(members...[I]);
|
||||
#else
|
||||
return detail::sequence_tuple::get<I>( detail::tie_as_tuple(val) );
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !BOOST_PFR_USE_CPP17
|
||||
#if !BOOST_PFR_USE_CPP17 && !BOOST_PFR_USE_CPP26
|
||||
/// \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 {
|
||||
static_assert(sizeof(T) && false, "====================> Boost.PFR: Calling boost::pfr::get on non const non assignable type is allowed only in C++17");
|
||||
static_assert(sizeof(T) && false, "====================> Boost.PFR: Calling boost::pfr::get on non const non assignable type is allowed only in C++17 and later");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
@@ -89,7 +89,7 @@ constexpr auto get(T&, std::enable_if_t<!std::is_assignable<T, T>::value>* = nul
|
||||
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
|
||||
auto &&[... members] = std::forward<T>(val);
|
||||
auto&& [... members] = std::forward<T>(val);
|
||||
return std::move(members...[I]);
|
||||
#else
|
||||
return std::move(detail::sequence_tuple::get<I>( detail::tie_as_tuple(val) ));
|
||||
@@ -107,18 +107,18 @@ 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
|
||||
#if !BOOST_PFR_USE_CPP17 && !BOOST_PFR_USE_CPP26
|
||||
, 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
|
||||
#if !BOOST_PFR_USE_CPP17 && !BOOST_PFR_USE_CPP26
|
||||
/// \overload get
|
||||
template <class U, class T>
|
||||
constexpr U& get(T&, std::enable_if_t<!std::is_assignable<T, T>::value>* = nullptr) noexcept {
|
||||
static_assert(sizeof(T) && false, "====================> Boost.PFR: Calling boost::pfr::get on non const non assignable type is allowed only in C++17");
|
||||
static_assert(sizeof(T) && false, "====================> Boost.PFR: Calling boost::pfr::get on non const non assignable type is allowed only in C++17 and later");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
@@ -163,7 +163,7 @@ using tuple_element_t = typename tuple_element<I, T>::type;
|
||||
template <class T>
|
||||
constexpr auto structure_to_tuple(const T& val) {
|
||||
#if BOOST_PFR_USE_CPP26
|
||||
const auto &[... members] = val;
|
||||
const auto& [... members] = val;
|
||||
return std::make_tuple(members...);
|
||||
#else
|
||||
return detail::make_stdtuple_from_tietuple(
|
||||
@@ -193,7 +193,7 @@ constexpr auto structure_to_tuple(const T& val) {
|
||||
template <class T>
|
||||
constexpr auto structure_tie(const T& val) noexcept {
|
||||
#if BOOST_PFR_USE_CPP26
|
||||
const auto &[... members] = val;
|
||||
const auto& [... members] = val;
|
||||
return std::tie(std::forward_like<const T &>(members)...);
|
||||
#else
|
||||
return detail::make_conststdtiedtuple_from_tietuple(
|
||||
@@ -207,12 +207,12 @@ 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
|
||||
#if !BOOST_PFR_USE_CPP17 && !BOOST_PFR_USE_CPP26
|
||||
, std::enable_if_t<std::is_assignable<T, T>::value>* = nullptr
|
||||
#endif
|
||||
) noexcept {
|
||||
#if BOOST_PFR_USE_CPP26
|
||||
auto &[... members] = val;
|
||||
auto& [... members] = val;
|
||||
return std::tie(std::forward_like<T &>(members)...);
|
||||
#else
|
||||
return detail::make_stdtiedtuple_from_tietuple(detail::tie_as_tuple(val),
|
||||
@@ -220,11 +220,11 @@ constexpr auto structure_tie(T& val
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !BOOST_PFR_USE_CPP17
|
||||
#if !BOOST_PFR_USE_CPP17 && !BOOST_PFR_USE_CPP26
|
||||
/// \overload structure_tie
|
||||
template <class T>
|
||||
constexpr auto structure_tie(T&, std::enable_if_t<!std::is_assignable<T, T>::value>* = nullptr) noexcept {
|
||||
static_assert(sizeof(T) && false, "====================> Boost.PFR: Calling boost::pfr::structure_tie on non const non assignable type is allowed only in C++17");
|
||||
static_assert(sizeof(T) && false, "====================> Boost.PFR: Calling boost::pfr::structure_tie on non const non assignable type is allowed only in C++17 and later modes");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -15,8 +15,7 @@
|
||||
namespace boost::pfr::detail {
|
||||
|
||||
template<class T>
|
||||
constexpr auto tie_as_tuple(T &val) noexcept
|
||||
{
|
||||
constexpr auto tie_as_tuple(T &val) 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.");
|
||||
@@ -24,6 +23,17 @@ constexpr auto tie_as_tuple(T &val) noexcept
|
||||
return sequence_tuple::tuple<std::add_lvalue_reference_t<decltype(members)>...>{members...};
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
@@ -332,20 +332,6 @@ constexpr std::size_t fields_count_lower_bound_unbounded(int, size_t_<0>) noexce
|
||||
#endif
|
||||
|
||||
///////////////////// Choosing between array size, unbounded binary search, and linear search followed by unbounded binary search.
|
||||
#if BOOST_PFR_USE_CPP26
|
||||
template<class T>
|
||||
constexpr auto fields_count_dispatch_impl(const T &t) noexcept
|
||||
{
|
||||
const auto &[... elts] = t;
|
||||
return std::integral_constant<std::size_t, sizeof...(elts)>{};
|
||||
}
|
||||
|
||||
template<class T>
|
||||
constexpr auto fields_count_dispatch() noexcept
|
||||
{
|
||||
return decltype(fields_count_dispatch_impl(std::declval<const T &>()))::value;
|
||||
}
|
||||
#else
|
||||
template <class T>
|
||||
constexpr auto fields_count_dispatch(long, long, std::false_type /*are_preconditions_met*/) noexcept {
|
||||
return 0;
|
||||
@@ -358,6 +344,27 @@ 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
|
||||
template<class T>
|
||||
constexpr auto fields_count_dispatch_impl(const T &t) noexcept
|
||||
{
|
||||
const auto &[... elts] = t;
|
||||
return std::integral_constant<std::size_t, sizeof...(elts)>{};
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
#else
|
||||
template <class T>
|
||||
constexpr auto fields_count_dispatch(long, int, std::true_type /*are_preconditions_met*/) noexcept
|
||||
-> decltype(sizeof(T{}))
|
||||
@@ -442,12 +449,8 @@ constexpr std::size_t fields_count() noexcept {
|
||||
constexpr bool no_errors =
|
||||
type_is_complete && type_is_not_a_reference && type_fields_are_move_constructible
|
||||
&& type_is_not_polymorphic && type_is_aggregate;
|
||||
#if BOOST_PFR_USE_CPP26
|
||||
constexpr std::size_t result = detail::fields_count_dispatch<type>();
|
||||
#else
|
||||
constexpr std::size_t result
|
||||
= detail::fields_count_dispatch<type>(1L, 1L, std::integral_constant<bool, no_errors>{});
|
||||
#endif
|
||||
detail::assert_first_not_base<type, result>(1L);
|
||||
|
||||
#ifndef __cpp_lib_is_aggregate
|
||||
|
||||
@@ -24,7 +24,8 @@ namespace boost { namespace pfr { namespace detail {
|
||||
template <class T, class F>
|
||||
constexpr void for_each_field(T&& value, F&& func) {
|
||||
#if BOOST_PFR_USE_CPP26
|
||||
if constexpr (std::is_aggregate_v<T> || std::is_bounded_array_v<std::remove_reference_t<T>>) {
|
||||
using no_ref = std::remove_reference_t<T>;
|
||||
if constexpr (std::is_aggregate_v<no_ref> || std::is_bounded_array_v<no_ref>) {
|
||||
auto &&[... members] = value;
|
||||
::boost::pfr::detail::for_each_field_impl(value,
|
||||
std::forward<F>(func),
|
||||
|
||||
@@ -21,23 +21,20 @@ namespace boost { namespace pfr { namespace detail {
|
||||
template <std::size_t Index>
|
||||
using size_t_ = std::integral_constant<std::size_t, Index >;
|
||||
|
||||
#if BOOST_PFR_USE_CPP26
|
||||
template<class T, class F, class I, class = decltype(std::declval<F>()(std::declval<T>(), I{}))>
|
||||
constexpr void for_each_field_impl_apply(T &&v, F &&f, I i, long)
|
||||
{
|
||||
template <class T, class F, class I, class = decltype(std::declval<F>()(std::declval<T>(), I{}))>
|
||||
constexpr void for_each_field_impl_apply(T&& v, F&& f, I i, long) {
|
||||
std::forward<F>(f)(std::forward<T>(v), i);
|
||||
}
|
||||
|
||||
template<class T, class F, class I>
|
||||
constexpr void for_each_field_impl_apply(T &&v, F &&f, I /*i*/, int)
|
||||
{
|
||||
template <class T, class F, class I>
|
||||
constexpr void for_each_field_impl_apply(T&& v, F&& f, I /*i*/, int) {
|
||||
std::forward<F>(f)(std::forward<T>(v));
|
||||
}
|
||||
|
||||
#if BOOST_PFR_USE_CPP26
|
||||
template<class T, class F, std::size_t... I>
|
||||
constexpr void for_each_field_impl(T &t, F &&f, std::index_sequence<I...>, auto move_values)
|
||||
{
|
||||
if constexpr (std::is_aggregate_v<T> || std::is_bounded_array_v<std::remove_reference_t<T>>) {
|
||||
constexpr void for_each_field_impl(T& t, F&& f, std::index_sequence<I...>, auto move_values) {
|
||||
if constexpr (std::is_aggregate_v<T> || std::is_bounded_array_v<T>) {
|
||||
auto &&[... members] = t;
|
||||
if constexpr (move_values)
|
||||
(detail::for_each_field_impl_apply(std::move(members...[I]),
|
||||
@@ -57,18 +54,7 @@ constexpr void for_each_field_impl(T &t, F &&f, std::index_sequence<I...>, auto
|
||||
(detail::for_each_field_impl_apply(t, std::forward<F>(f), size_t_<I>{}, 1L), ...);
|
||||
}
|
||||
}
|
||||
#else
|
||||
template <class T, class F, class I, class = decltype(std::declval<F>()(std::declval<T>(), I{}))>
|
||||
constexpr void for_each_field_impl_apply(T&& v, F&& f, I i, long) {
|
||||
std::forward<F>(f)(std::forward<T>(v), i);
|
||||
}
|
||||
|
||||
template <class T, class F, class I>
|
||||
constexpr void for_each_field_impl_apply(T&& v, F&& f, I /*i*/, int) {
|
||||
std::forward<F>(f)(std::forward<T>(v));
|
||||
}
|
||||
|
||||
#if !defined(__cpp_fold_expressions) || __cpp_fold_expressions < 201603
|
||||
#elif !defined(__cpp_fold_expressions) || __cpp_fold_expressions < 201603
|
||||
template <class T, class F, std::size_t... I>
|
||||
constexpr void for_each_field_impl(T& t, F&& f, std::index_sequence<I...>, std::false_type /*move_values*/) {
|
||||
const int v[] = {0, (
|
||||
@@ -98,7 +84,6 @@ constexpr void for_each_field_impl(T& t, F&& f, std::index_sequence<I...>, std::
|
||||
(detail::for_each_field_impl_apply(sequence_tuple::get<I>(std::move(t)), std::forward<F>(f), size_t_<I>{}, 1L), ...);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}}} // namespace boost::pfr::detail
|
||||
|
||||
#endif // BOOST_PFR_DETAIL_FOR_EACH_FIELD_IMPL_HPP
|
||||
|
||||
@@ -54,7 +54,7 @@ local REQUIRE_LOOPHOLE =
|
||||
;
|
||||
local REQUIRE_VSB =
|
||||
[ check-target-builds ../core//compiler_supports_vsb : : <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 ] ;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Antony Polukhin
|
||||
// Copyright (c) 2024-2025 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)
|
||||
@@ -9,11 +9,7 @@
|
||||
#include <cstdint>
|
||||
|
||||
#if defined(__clang__)
|
||||
# if SIZE_MAX > (1ULL << 32) - 1
|
||||
# define ARRAY_MAX (SIZE_MAX >> 3)
|
||||
# else
|
||||
# define ARRAY_MAX SIZE_MAX
|
||||
# endif
|
||||
# define ARRAY_MAX INT_MAX
|
||||
# define OBJECT_MAX SIZE_MAX
|
||||
#elif defined(__GNUC__)
|
||||
# define ARRAY_MAX INT_MAX
|
||||
|
||||
@@ -23,7 +23,7 @@ int main() {
|
||||
// FIXME: https://github.com/boostorg/pfr/issues/131
|
||||
#if defined(__clang__) && __cplusplus >= 202002L
|
||||
|
||||
# if BOOST_PFR_USE_LOOPHOLE == 0 && BOOST_PFR_USE_CPP17 == 0
|
||||
# if BOOST_PFR_USE_LOOPHOLE == 0 && BOOST_PFR_USE_CPP17 == 0 && BOOST_PFR_USE_CPP26 == 0
|
||||
# error This test should fail on classic engine
|
||||
#endif
|
||||
|
||||
|
||||
@@ -18,8 +18,8 @@ struct aggr {
|
||||
zero_array a;
|
||||
};
|
||||
|
||||
static_assert(sizeof(zero_array) == 0);
|
||||
static_assert(sizeof(aggr) == 0);
|
||||
static_assert(sizeof(zero_array) == 0, "");
|
||||
static_assert(sizeof(aggr) == 0, "");
|
||||
|
||||
int main() {
|
||||
aggr a;
|
||||
|
||||
@@ -6,6 +6,11 @@
|
||||
// Detection of variadic structured binding support
|
||||
|
||||
#include <type_traits>
|
||||
#include <version>
|
||||
|
||||
#if !(__cpp_structured_bindings >= 202411L && __cpp_lib_forward_like >= 202207L)
|
||||
#error Compiler does not support the required features
|
||||
#endif
|
||||
|
||||
struct MyPair {
|
||||
int first;
|
||||
@@ -21,3 +26,4 @@ auto test() {
|
||||
int main() {
|
||||
return ::test<MyPair>();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user