mirror of
https://github.com/boostorg/pfr.git
synced 2026-01-19 16:32:13 +00:00
Compare commits
4 Commits
develop
...
tuple_get_
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
442928eeb4 | ||
|
|
d4095b3fbd | ||
|
|
19d5a1d0e6 | ||
|
|
e002e42910 |
@@ -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)) );
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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
@@ -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<
|
||||
|
||||
@@ -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()
|
||||
|
||||
80
test/core/run/tuple_types_match.cpp
Normal file
80
test/core/run/tuple_types_match.cpp
Normal 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();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user