mirror of
https://github.com/boostorg/pfr.git
synced 2026-01-20 04:42:22 +00:00
Compare commits
4 Commits
2.1.0
...
tuple_get_
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
442928eeb4 | ||
|
|
d4095b3fbd | ||
|
|
19d5a1d0e6 | ||
|
|
e002e42910 |
@@ -45,8 +45,6 @@ Outputs:
|
||||
Edgar Allan Poe was born in 1809
|
||||
```
|
||||
|
||||
[Run the above sample](https://godbolt.org/z/PfYsWKb7v)
|
||||
|
||||
|
||||
### Motivating Example #1
|
||||
```c++
|
||||
|
||||
@@ -34,9 +34,7 @@ local doxygen_params =
|
||||
\"podops=\\b See \\b Also : \\xmlonly<link linkend='boost_pfr.tutorial.three_ways_of_getting_operators'>\\endxmlonly 'Three ways of getting operators' \\xmlonly</link>\\endxmlonly\" \\
|
||||
\"customio=\\b See \\b Also : \\xmlonly<link linkend='boost_pfr.tutorial.custom_printing_of_aggregates'>\\endxmlonly 'Custom printing of aggregates' \\xmlonly</link>\\endxmlonly for info on how to implement your own manipulator with custom format.\" \\
|
||||
\"aggregate=\\xmlonly<link linkend='boost_pfr.limitations_and_configuration'>\\endxmlonly simple aggregate \\xmlonly</link>\\endxmlonly\" \\
|
||||
"
|
||||
<doxygen:param>"PREDEFINED= \\
|
||||
\"BOOST_PFR_DOXYGEN_INVOKED=1\" \\
|
||||
\"BOOST_PFR_DOXYGEN_INVOKED\" \\
|
||||
"
|
||||
;
|
||||
|
||||
@@ -54,7 +52,7 @@ boostbook pfr-doc
|
||||
pfr.qbk
|
||||
:
|
||||
<dependency>autodoc_pfr
|
||||
<xsl:param>boost.root=https://www.boost.org/doc/libs/1_81_0
|
||||
<xsl:param>boost.root=https://www.boost.org/doc/libs/1_72_0
|
||||
#<xsl:param>boost.root=../../../.
|
||||
<xml:param>html.stylesheet=../../../../doc/src/boostbook.css
|
||||
;
|
||||
|
||||
40
doc/pfr.qbk
40
doc/pfr.qbk
@@ -1,6 +1,6 @@
|
||||
[library Boost.PFR
|
||||
[quickbook 1.6]
|
||||
[version 2.1]
|
||||
[version 2.0]
|
||||
[copyright 2016-2023 Antony Polukhin]
|
||||
[category Language Features Emulation]
|
||||
[license
|
||||
@@ -17,7 +17,6 @@ Boost.PFR is a C++14 library for a very basic reflection. It gives you access to
|
||||
[import ../example/motivating_example0.cpp]
|
||||
[pfr_motivating_example]
|
||||
|
||||
Experiment with the sample [@https://godbolt.org/z/PfYsWKb7v online].
|
||||
See [link boost_pfr.limitations_and_configuration [*limitations]].
|
||||
|
||||
|
||||
@@ -43,20 +42,20 @@ user_info retrieve_friend(std::string_view name) {
|
||||
name
|
||||
);
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
user_info info {
|
||||
std::move(std::get<0>(info_tuple)),
|
||||
std::move(std::get<1>(info_tuple)),
|
||||
std::move(std::get<2>(info_tuple)),
|
||||
std::move(std::get<3>(info_tuple)),
|
||||
}
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
auto friend_info = ask_user_for_friend(std::move(info));
|
||||
|
||||
db::insert(
|
||||
"INSERT INTO user_infos(id, name, email, login) VALUES ($0, $1, $2, $3)",
|
||||
friend_info.id, //////////////////////////////////////////////////////
|
||||
friend_info.id, /////////////////////////////////////////////////////////
|
||||
friend_info.name, // Users are forced to enumerate fields because your
|
||||
friend_info.email, // library can not iterate over the fields of a user
|
||||
friend_info.login // provided structure
|
||||
@@ -81,20 +80,20 @@ user_info retrieve_friend(std::string_view name) {
|
||||
name
|
||||
);
|
||||
|
||||
////////////////// No boilerplate code to move data around //////////////////
|
||||
////////////////// No boilerplate code to move data around /////////////////////
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
auto friend_info = ask_user_for_friend(std::move(info));
|
||||
|
||||
db::insert(
|
||||
"INSERT INTO user_infos(id, name, email, login) VALUES ($0, $1, $2, $3)",
|
||||
friend_info /////////////////////////////////////////////////////////
|
||||
friend_info ////////////////////////////////////////////////////////////
|
||||
// Boost.PFR allows you to iterate over all the fields
|
||||
// of a user provided structure
|
||||
//
|
||||
@@ -120,7 +119,7 @@ struct user_info {
|
||||
std::string name, email, login;
|
||||
};
|
||||
|
||||
/// Customizations via hand-written code ////////////////////////////////////////
|
||||
/// Customizations via hand-written code or macro like BOOST_FUSION_ADAPT_STRUCT ///
|
||||
auto db_api_tie(user_info& ui) noexcept {
|
||||
return std::tie(ui.id, ui.name, ui.email, ui.login);
|
||||
}
|
||||
@@ -128,7 +127,7 @@ auto db_api_tie(user_info& ui) noexcept {
|
||||
auto db_api_tie(const user_info& ui) noexcept {
|
||||
return std::tie(ui.id, ui.name, ui.email, ui.login);
|
||||
}
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////////
|
||||
```
|
||||
][
|
||||
```
|
||||
@@ -139,7 +138,7 @@ struct user_info {
|
||||
std::string name, email, login;
|
||||
};
|
||||
|
||||
//////// With Boost.PFR there's no need in hand written customizations //////////
|
||||
//////// With Boost.PFR there's no need in hand written customizations /////////////
|
||||
|
||||
|
||||
|
||||
@@ -147,29 +146,14 @@ struct user_info {
|
||||
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////////
|
||||
```
|
||||
]]
|
||||
]
|
||||
|
||||
|
||||
Imagine that you are writing a serialization library. Serialization of user
|
||||
provided structures (and nested structures) with Boost.PFR it is just as simple as:
|
||||
|
||||
```
|
||||
void Write(Writer& writer, int value);
|
||||
void Write(Writer& writer, std::string_view value);
|
||||
|
||||
template <typename T>
|
||||
std::enable_if_t<std::is_aggregate_v<T>> Write(Writer& writer, const T& value) {
|
||||
boost::pfr::for_each_field(
|
||||
value, [&writer](const auto& field) { Write(writer, field); });
|
||||
}
|
||||
```
|
||||
|
||||
With Boost.PFR the code is shorter, more readable and more pleasant to write.
|
||||
|
||||
[note All the above examples were inspired by the Boost.PFR usage in [@https://github.com/userver-framework/userver 🐙 userver framework].]
|
||||
|
||||
|
||||
[h2 Out of the box functionality ]
|
||||
@@ -180,7 +164,7 @@ Boost.PFR adds the following out-of-the-box functionality for aggregate initiali
|
||||
* heterogeneous comparators
|
||||
* hash
|
||||
* IO streaming
|
||||
* access to members by index or type
|
||||
* access to members by index
|
||||
* member type retrieval
|
||||
* methods for cooperation with `std::tuple`
|
||||
* methods to visit each field of the structure
|
||||
|
||||
@@ -91,7 +91,7 @@ void test_examples() {
|
||||
|
||||
{
|
||||
//[pfr_quick_examples_get
|
||||
// Get field by index/type and assign new value to that field
|
||||
// Get field by index and assign new value to that field
|
||||
|
||||
struct sample {
|
||||
char c;
|
||||
@@ -100,9 +100,8 @@ void test_examples() {
|
||||
|
||||
sample var{};
|
||||
boost::pfr::get<1>(var) = 42.01f;
|
||||
boost::pfr::get<char>(var) = 'A';
|
||||
|
||||
std::cout << var.c << var.f; // Outputs: A 42.01
|
||||
std::cout << var.f; // Outputs: 42.01
|
||||
//]
|
||||
}
|
||||
|
||||
|
||||
@@ -30,25 +30,20 @@
|
||||
namespace boost { namespace pfr {
|
||||
|
||||
/// \brief Returns reference or const reference to a field with index `I` in \aggregate `val`.
|
||||
/// Overload taking the type `U` returns reference or const reference to a field
|
||||
/// with provided type `U` in \aggregate `val` if there's only one field of such type in `val`.
|
||||
///
|
||||
/// \b Example:
|
||||
/// \code
|
||||
/// struct my_struct { int i, short s; };
|
||||
/// my_struct s {10, 11};
|
||||
///
|
||||
/// assert(boost::pfr::get<0>(s) == 10);
|
||||
/// boost::pfr::get<1>(s) = 0;
|
||||
///
|
||||
/// assert(boost::pfr::get<int>(s) == 10);
|
||||
/// boost::pfr::get<short>(s) = 11;
|
||||
/// \endcode
|
||||
template <std::size_t I, class T>
|
||||
constexpr decltype(auto) get(const T& val) noexcept {
|
||||
return detail::sequence_tuple::get<I>( detail::tie_as_tuple(val) );
|
||||
}
|
||||
|
||||
|
||||
/// \overload get
|
||||
template <std::size_t I, class T>
|
||||
constexpr decltype(auto) get(T& val
|
||||
@@ -71,42 +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) ));
|
||||
}
|
||||
|
||||
|
||||
/// \overload get
|
||||
template <class U, class T>
|
||||
constexpr const U& get(const T& val) noexcept {
|
||||
return detail::sequence_tuple::get_by_type_impl<const U&>( detail::tie_as_tuple(val) );
|
||||
}
|
||||
|
||||
|
||||
/// \overload get
|
||||
template <class U, class T>
|
||||
constexpr U& get(T& val
|
||||
#if !BOOST_PFR_USE_CPP17
|
||||
, 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
|
||||
/// \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");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/// \overload get
|
||||
template <class U, class T>
|
||||
constexpr U&& get(T&& val, std::enable_if_t< std::is_rvalue_reference<T&&>::value>* = nullptr) noexcept {
|
||||
return std::move(detail::sequence_tuple::get_by_type_impl<U&>( 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)) );
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@ namespace typeid_conversions {
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning( push )
|
||||
// '<<': check operator precedence for possible error; use parentheses to clarify precedence
|
||||
# pragma warning( disable : 4554 )
|
||||
# pragma warning( disable : 4554 )
|
||||
#endif
|
||||
|
||||
constexpr std::size_t native_types_mask = 31;
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
// The Great Type Loophole (C++14)
|
||||
// Initial implementation by Alexandr Poltavsky, http://alexpolt.github.io
|
||||
//
|
||||
// Description:
|
||||
// Description:
|
||||
// The Great Type Loophole is a technique that allows to exchange type information with template
|
||||
// instantiations. Basically you can assign and read type information during compile time.
|
||||
// Here it is used to detect data members of a data type. I described it for the first time in
|
||||
|
||||
@@ -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
@@ -20,8 +20,6 @@ constexpr decltype(is_reflectable<T, WhatFor>::value) possible_reflectable(long)
|
||||
return is_reflectable<T, WhatFor>::value;
|
||||
}
|
||||
|
||||
#if BOOST_PFR_ENABLE_IMPLICIT_REFLECTION
|
||||
|
||||
template <class T, class WhatFor>
|
||||
constexpr bool possible_reflectable(int) noexcept {
|
||||
# if defined(__cpp_lib_is_aggregate)
|
||||
@@ -32,16 +30,6 @@ constexpr bool possible_reflectable(int) noexcept {
|
||||
# endif
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
template <class T, class WhatFor>
|
||||
constexpr bool possible_reflectable(int) noexcept {
|
||||
// negative answer here won't change behaviour in PFR-dependent libraries(like Fusion)
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}}} // namespace boost::pfr::detail
|
||||
|
||||
#endif // BOOST_PFR_DETAIL_POSSIBLE_REFLECTABLE_HPP
|
||||
|
||||
@@ -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,45 +78,12 @@ constexpr T&& get_impl(base_from_member<N, T>&& t) noexcept {
|
||||
return std::forward<T>(t.value);
|
||||
}
|
||||
|
||||
|
||||
template <class T, std::size_t N>
|
||||
constexpr T& get_by_type_impl(base_from_member<N, T>& t) noexcept {
|
||||
// NOLINTNEXTLINE(clang-analyzer-core.uninitialized.UndefReturn)
|
||||
return t.value;
|
||||
}
|
||||
|
||||
template <class T, std::size_t N>
|
||||
constexpr const T& get_by_type_impl(const base_from_member<N, T>& t) noexcept {
|
||||
// NOLINTNEXTLINE(clang-analyzer-core.uninitialized.UndefReturn)
|
||||
return t.value;
|
||||
}
|
||||
|
||||
template <class T, std::size_t N>
|
||||
constexpr volatile T& get_by_type_impl(volatile base_from_member<N, T>& t) noexcept {
|
||||
// NOLINTNEXTLINE(clang-analyzer-core.uninitialized.UndefReturn)
|
||||
return t.value;
|
||||
}
|
||||
|
||||
template <class T, std::size_t N>
|
||||
constexpr const volatile T& get_by_type_impl(const volatile base_from_member<N, T>& t) noexcept {
|
||||
// NOLINTNEXTLINE(clang-analyzer-core.uninitialized.UndefReturn)
|
||||
return t.value;
|
||||
}
|
||||
|
||||
template <class T, std::size_t N>
|
||||
constexpr T&& get_by_type_impl(base_from_member<N, T>&& t) noexcept {
|
||||
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 T, std::size_t N>
|
||||
constexpr const T&& get_by_type_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<
|
||||
|
||||
@@ -19,8 +19,8 @@
|
||||
|
||||
namespace boost { namespace pfr {
|
||||
|
||||
/// Has a static const member variable `value` when it is known that type T can or can't be reflected using Boost.PFR; otherwise, there is no member variable.
|
||||
/// Every user may (and in some difficult cases - should) specialize is_reflectable on his own.
|
||||
/// Has a static const member variable `value` when it known that type T can or can't be reflected using Boost.PFR; otherwise, there is no member variable.
|
||||
/// Every user may(and in some difficult cases - should) specialize is_reflectable on his own.
|
||||
///
|
||||
/// \b Example:
|
||||
/// \code
|
||||
@@ -29,9 +29,11 @@ namespace boost { namespace pfr {
|
||||
/// template<> struct is_reflectable<B, boost_fusion_tag> : std::false_type {}; // 'B' won't be interpreted as reflectable in only Boost Fusion
|
||||
/// }}
|
||||
/// \endcode
|
||||
/// \note is_reflectable affects is_implicitly_reflectable, the decision made by is_reflectable is used by is_implicitly_reflectable.
|
||||
/// \note is_reflectable affects is_implicitly_reflectable, the decision made by is_reflectable has more priority than is_implicitly_reflectable,
|
||||
/// because is_reflectable is more sharp than is_implicitly_reflectable
|
||||
///
|
||||
template<class T, class WhatFor>
|
||||
struct is_reflectable { /* does not have 'value' because value is unknown */ };
|
||||
struct is_reflectable { /* do not has 'value' because value is unknown */ };
|
||||
|
||||
// these specs can't be inherited from 'std::integral_constant< bool, boost::pfr::is_reflectable<T, WhatFor>::value >',
|
||||
// because it will break the sfinae-friendliness
|
||||
@@ -44,15 +46,17 @@ struct is_reflectable<volatile T, WhatFor> : boost::pfr::is_reflectable<T, WhatF
|
||||
template<class T, class WhatFor>
|
||||
struct is_reflectable<const volatile T, WhatFor> : boost::pfr::is_reflectable<T, WhatFor> {};
|
||||
|
||||
#if BOOST_PFR_ENABLE_IMPLICIT_REFLECTION
|
||||
/// Checks the input type for the potential to be reflected.
|
||||
/// Specialize is_reflectable if you disagree with is_implicitly_reflectable's default decision.
|
||||
/// Specialize is_reflectable if you are disagree with is_implicitly_reflectable's default decision.
|
||||
template<class T, class WhatFor>
|
||||
using is_implicitly_reflectable = std::integral_constant< bool, boost::pfr::detail::possible_reflectable<T, WhatFor>(1L) >;
|
||||
|
||||
/// Checks the input type for the potential to be reflected.
|
||||
/// Specialize is_reflectable if you disagree with is_implicitly_reflectable_v's default decision.
|
||||
/// Specialize is_reflectable if you are disagree with is_implicitly_reflectable_v's default decision.
|
||||
template<class T, class WhatFor>
|
||||
constexpr bool is_implicitly_reflectable_v = is_implicitly_reflectable<T, WhatFor>::value;
|
||||
#endif
|
||||
|
||||
}} // namespace boost::pfr
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -1,67 +0,0 @@
|
||||
// Copyright (c) 2020-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>
|
||||
|
||||
namespace testing {
|
||||
|
||||
namespace {
|
||||
|
||||
struct Aggregate {
|
||||
int a;
|
||||
const int b;
|
||||
double c;
|
||||
double d;
|
||||
short e;
|
||||
};
|
||||
|
||||
void test_get_by_type() {
|
||||
#if BOOST_PFR_USE_CPP17
|
||||
Aggregate t{1, 2, 3.4, 5.6, 7};
|
||||
|
||||
BOOST_TEST_EQ(boost::pfr::get<int>(t), 1);
|
||||
BOOST_TEST_EQ(boost::pfr::get<const int>(t), 2);
|
||||
BOOST_TEST_EQ(boost::pfr::get<short>(t), 7);
|
||||
|
||||
boost::pfr::get<int>(t) = 11;
|
||||
boost::pfr::get<short>(t) = 77;
|
||||
#endif
|
||||
}
|
||||
|
||||
void test_const_get_by_type() {
|
||||
#if BOOST_PFR_USE_CPP17 || BOOST_PFR_USE_LOOPHOLE
|
||||
const Aggregate t{1, 2, 3.4, 5.6, 7};
|
||||
BOOST_TEST_EQ(boost::pfr::get<short>(t), 7);
|
||||
#endif
|
||||
}
|
||||
|
||||
void test_get_by_type_pod() {
|
||||
struct PodAggregate {
|
||||
int i;
|
||||
short s;
|
||||
};
|
||||
|
||||
PodAggregate pod{1, 2};
|
||||
BOOST_TEST_EQ(boost::pfr::get<int>(pod), 1);
|
||||
BOOST_TEST_EQ(boost::pfr::get<short>(pod), 2);
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
|
||||
} // namespace testing
|
||||
|
||||
int main() {
|
||||
testing::test_get_by_type();
|
||||
testing::test_const_get_by_type();
|
||||
testing::test_get_by_type_pod();
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
// Test case for https://github.com/boostorg/pfr/issues/33
|
||||
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <boost/pfr.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
|
||||
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