2
0
mirror of https://github.com/boostorg/pfr.git synced 2026-01-19 16:32:13 +00:00

Compare commits

...

4 Commits

Author SHA1 Message Date
Antony Polukhin
442928eeb4 fixes 2023-02-14 09:23:15 +03:00
Antony Polukhin
d4095b3fbd update the generation script 2023-02-12 19:46:27 +03:00
Antony Polukhin
19d5a1d0e6 test fixes 2023-02-12 19:39:49 +03:00
Antony Polukhin
e002e42910 make the result type of boost::pfr::get exactly match std::get 2023-02-11 21:52:40 +03:00
6 changed files with 377 additions and 243 deletions

View File

@@ -66,8 +66,8 @@ 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 {
return std::move(detail::sequence_tuple::get<I>( detail::tie_as_tuple(val) ));
constexpr decltype(auto) get(T&& val, std::enable_if_t< std::is_rvalue_reference<T&&>::value>* = nullptr) noexcept {
return detail::sequence_tuple::get<I>( detail::tie_as_tuple(std::forward<T>(val)) );
}

View File

@@ -52,10 +52,20 @@ constexpr auto tie_as_tuple(T& val) noexcept {
!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."
);
typedef size_t_<boost::pfr::detail::fields_count<T>()> fields_count_tag;
typedef size_t_<boost::pfr::detail::fields_count< T >()> fields_count_tag;
return boost::pfr::detail::tie_as_tuple(val, fields_count_tag{});
}
template <class T>
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."
);
typedef size_t_<boost::pfr::detail::fields_count< T >()> fields_count_tag;
return boost::pfr::detail::tie_as_tuple(std::forward<T>(val), fields_count_tag{});
}
template <class T, class F, std::size_t... I>
void for_each_field_dispatcher(T& t, F&& f, std::index_sequence<I...>) {
static_assert(

File diff suppressed because it is too large Load Diff

View File

@@ -39,7 +39,7 @@ struct tuple_base< std::index_sequence<I...>, Tail... >
constexpr tuple_base(const tuple_base&) = default;
constexpr tuple_base(Tail... v) noexcept
: base_from_member<I, Tail>{ v }...
: base_from_member<I, Tail>{ static_cast<Tail>(v) }...
{}
};
@@ -78,6 +78,12 @@ constexpr T&& get_impl(base_from_member<N, T>&& t) noexcept {
return std::forward<T>(t.value);
}
template <std::size_t N, class T>
constexpr const T&& get_impl(const base_from_member<N, T>&& t) noexcept {
// NOLINTNEXTLINE(clang-analyzer-core.uninitialized.UndefReturn)
return std::forward<T>(t.value);
}
template <class ...Values>
struct tuple: tuple_base<

View File

@@ -44,47 +44,66 @@ namespace boost { namespace pfr { namespace detail {
template <class... Args>
constexpr auto make_tuple_of_references(Args&&... args) noexcept {
return sequence_tuple::tuple<Args&...>{ args... };
return sequence_tuple::tuple<Args&&...>{ static_cast<Args&&>(args)... };
}
template<typename T, typename Arg>
constexpr decltype(auto) add_cv_like(Arg& arg) noexcept {
if constexpr (std::is_const<T>::value && std::is_volatile<T>::value) {
return const_cast<const volatile Arg&>(arg);
}
else if constexpr (std::is_const<T>::value) {
return const_cast<const Arg&>(arg);
}
else if constexpr (std::is_volatile<T>::value) {
return const_cast<volatile Arg&>(arg);
}
else {
return const_cast<Arg&>(arg);
if constexpr (std::is_rvalue_reference<T&&>::value) {
if constexpr (std::is_const<T>::value && std::is_volatile<T>::value) {
return const_cast<const volatile Arg&&>(arg);
}
else if constexpr (std::is_const<T>::value) {
return const_cast<const Arg&&>(arg);
}
else if constexpr (std::is_volatile<T>::value) {
return const_cast<volatile Arg&&>(arg);
}
else {
return const_cast<Arg&&>(arg);
}
} else {
if constexpr (std::is_const<T>::value && std::is_volatile<T>::value) {
return const_cast<const volatile Arg&>(arg);
}
else if constexpr (std::is_const<T>::value) {
return const_cast<const Arg&>(arg);
}
else if constexpr (std::is_volatile<T>::value) {
return const_cast<volatile Arg&>(arg);
}
else {
return const_cast<Arg&>(arg);
}
}
}
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=78939
template<typename T, typename Sb, typename Arg>
constexpr decltype(auto) workaround_cast(Arg& arg) noexcept {
using output_arg_t = std::conditional_t<!std::is_reference<Sb>(), decltype(detail::add_cv_like<T>(arg)), Sb>;
using output_arg_t = std::conditional_t<
!std::is_reference<Sb>(),
decltype(detail::add_cv_like<T>(arg)),
std::conditional_t<std::is_rvalue_reference<T&&>::value, Sb&&, Sb&>
>;
return const_cast<output_arg_t>(arg);
}
template <class T>
constexpr auto tie_as_tuple(T& /*val*/, size_t_<0>) noexcept {
constexpr auto tie_as_tuple(const T& /*val*/, size_t_<0>) noexcept {
return sequence_tuple::tuple<>{};
}
template <class T>
constexpr auto tie_as_tuple(T& val, size_t_<1>, std::enable_if_t<std::is_class< std::remove_cv_t<T> >::value>* = nullptr) noexcept {
auto& [a] = const_cast<std::remove_cv_t<T>&>(val); // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
constexpr auto tie_as_tuple(T&& val, size_t_<1>, std::enable_if_t<std::is_class< std::remove_cv_t<T> >::value>* = nullptr) noexcept {
auto&& [a] = const_cast<std::remove_cv_t<T>&>(val); // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.
return ::boost::pfr::detail::make_tuple_of_references(detail::workaround_cast<T, decltype(a)>(a));
}
template <class T>
constexpr auto tie_as_tuple(T& val, size_t_<1>, std::enable_if_t<!std::is_class< std::remove_cv_t<T> >::value>* = nullptr) noexcept {
return ::boost::pfr::detail::make_tuple_of_references( val );
constexpr auto tie_as_tuple(T&& val, size_t_<1>, std::enable_if_t<!std::is_class< std::remove_cv_t<T> >::value>* = nullptr) noexcept {
return ::boost::pfr::detail::make_tuple_of_references( std::forward<T>(val) );
}
"""
@@ -92,7 +111,7 @@ constexpr auto tie_as_tuple(T& val, size_t_<1>, std::enable_if_t<!std::is_class<
############################################################################################################################
EPILOGUE = """
template <class T, std::size_t I>
constexpr void tie_as_tuple(T& /*val*/, size_t_<I>) noexcept {
constexpr void tie_as_tuple(T&& /*val*/, size_t_<I>) noexcept {
static_assert(sizeof(T) && false,
"====================> Boost.PFR: Too many fields in a structure T. Regenerate include/boost/pfr/detail/core17_generated.hpp file for appropriate count of fields. For example: `python ./misc/generate_cpp17.py 300 > include/boost/pfr/detail/core17_generated.hpp`");
}
@@ -151,11 +170,11 @@ for i in range(1, funcs_count):
empty_printer = EmptyLinePrinter()
print("template <class T>")
print("constexpr auto tie_as_tuple(T& val, size_t_<" + str(i + 1) + ">) noexcept {")
print("constexpr auto tie_as_tuple(T&& val, size_t_<" + str(i + 1) + ">) noexcept {")
if i < max_args_on_a_line:
print(" auto& [" + indexes.strip() + "] = const_cast<std::remove_cv_t<T>&>(val); // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.")
print(" auto&& [" + indexes.strip() + "] = const_cast<std::remove_cv_t<T>&>(val); // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.")
else:
print(" auto& [")
print(" auto&& [")
print(indexes)
print(" ] = const_cast<std::remove_cv_t<T>&>(val); // ====================> Boost.PFR: User-provided type is not a SimpleAggregate.")
empty_printer.print_once()

View File

@@ -0,0 +1,80 @@
// Copyright (c) 2016-2023 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)
#include <boost/pfr/core.hpp>
#include <boost/core/lightweight_test.hpp>
#include <tuple>
#include <type_traits>
template <class T, class U>
void test_get_matches_tuple(T x, U y) {
const auto& x_cref = x;
const auto& y_cref = y;
BOOST_TEST_EQ(boost::pfr::get<0>(x), std::get<0>(y));
BOOST_TEST_EQ(boost::pfr::get<1>(x), std::get<1>(y));
BOOST_TEST_EQ(boost::pfr::get<0>(x_cref), std::get<0>(y_cref));
BOOST_TEST_EQ(boost::pfr::get<1>(x_cref), std::get<1>(y_cref));
BOOST_TEST_EQ(boost::pfr::get<0>(std::move(x_cref)), std::get<0>(std::move(y_cref)));
BOOST_TEST_EQ(boost::pfr::get<1>(std::move(x_cref)), std::get<1>(std::move(y_cref)));
BOOST_TEST_EQ(boost::pfr::get<0>(std::move(x)), std::get<0>(std::move(y)));
BOOST_TEST_EQ(boost::pfr::get<1>(std::move(x)), std::get<1>(std::move(y)));
static_assert(std::is_same<decltype(boost::pfr::get<0>(x)), decltype(std::get<0>(y))>::value, "");
static_assert(std::is_same<decltype(boost::pfr::get<1>(x)), decltype(std::get<1>(y))>::value, "");
static_assert(std::is_same<decltype(boost::pfr::get<0>(x_cref)), decltype(std::get<0>(y_cref))>::value, "");
static_assert(std::is_same<decltype(boost::pfr::get<1>(x_cref)), decltype(std::get<1>(y_cref))>::value, "");
static_assert(std::is_same<decltype(boost::pfr::get<0>(std::move(x_cref))), decltype(std::get<0>(std::move(y_cref)))>::value, "");
static_assert(std::is_same<decltype(boost::pfr::get<1>(std::move(x_cref))), decltype(std::get<1>(std::move(y_cref)))>::value, "");
static_assert(std::is_same<decltype(boost::pfr::get<0>(std::move(x))), decltype(std::get<0>(std::move(y)))>::value, "");
static_assert(std::is_same<decltype(boost::pfr::get<1>(std::move(x))), decltype(std::get<1>(std::move(y)))>::value, "");
// TODO: seems to take a lot of effort with close to 0 profit
//static_assert(std::is_same<boost::pfr::tuple_element_t<0, T>, std::tuple_element_t<0, U> >::value, "");
//static_assert(std::is_same<boost::pfr::tuple_element_t<1, T>, std::tuple_element_t<1, U> >::value, "");
//static_assert(std::is_same<boost::pfr::tuple_element_t<0, const T>, std::tuple_element_t<0, const U> >::value, "");
//static_assert(std::is_same<boost::pfr::tuple_element_t<1, const T>, std::tuple_element_t<1, const U> >::value, "");
}
int main() {
#if BOOST_PFR_USE_CPP17
struct aggregate { int first; char second; };
struct aggregate_const { const int first; const char second; };
test_get_matches_tuple(aggregate{1, 2}, std::tuple<int, char>{1, 2});
test_get_matches_tuple(aggregate_const{1, 2}, std::tuple<const int, const char>{1, 2});
int first = 1; char second;
struct aggregate_ref { int& first; char& second; };
struct aggregate_const_ref { const int& first; const char& second; };
test_get_matches_tuple(
aggregate_ref{first, second},
std::tuple<int&, char&>{first, second}
);
test_get_matches_tuple(
aggregate_const_ref{first, second},
std::tuple<const int&, const char&>{first, second}
);
struct aggregate_rref { int&& first; char&& second; };
struct aggregate_const_rref { const int&& first; const char&& second; };
test_get_matches_tuple(
aggregate_rref{std::move(first), std::move(second)},
std::tuple<int&&, char&&>{std::move(first), std::move(second)}
);
test_get_matches_tuple(
aggregate_const_rref{std::move(first), std::move(second)},
std::tuple<const int&&, const char&&>{std::move(first), std::move(second)}
);
#endif // #if BOOST_PFR_USE_CPP17
return boost::report_errors();
}