2
0
mirror of https://github.com/boostorg/pfr.git synced 2026-01-21 05:02:15 +00:00

Compare commits

...

6 Commits

Author SHA1 Message Date
René Ferdinand Rivera Morell
b0bf18798c Fix missing include for unique_ptr. (#125) 2023-03-07 09:33:06 +03:00
Antony Polukhin
9bc057e2a6 remove trailing whitespaces 2023-03-03 15:46:10 +03:00
Antony Polukhin
e460ce2ddc Always define is_implicitly_reflectable (#124)
Always define is_implicitly_reflectable
2023-02-27 10:59:34 +03:00
Antony Polukhin
d66c0a9551 Fix macro definition for Doxygen 2023-02-26 13:07:45 +03:00
Antony Polukhin
95c06fb7c6 Update the docs with more samples and links to online playgrounds 2023-02-26 12:58:08 +03:00
Antony Polukhin
ab509a5b32 implement pfr::get by type (#123) 2023-02-21 14:28:28 +03:00
12 changed files with 204 additions and 29 deletions

View File

@@ -45,6 +45,8 @@ Outputs:
Edgar Allan Poe was born in 1809
```
[Run the above sample](https://godbolt.org/z/PfYsWKb7v)
### Motivating Example #1
```c++

View File

@@ -34,7 +34,9 @@ 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\" \\
\"BOOST_PFR_DOXYGEN_INVOKED\" \\
"
<doxygen:param>"PREDEFINED= \\
\"BOOST_PFR_DOXYGEN_INVOKED=1\" \\
"
;
@@ -52,7 +54,7 @@ boostbook pfr-doc
pfr.qbk
:
<dependency>autodoc_pfr
<xsl:param>boost.root=https://www.boost.org/doc/libs/1_72_0
<xsl:param>boost.root=https://www.boost.org/doc/libs/1_81_0
#<xsl:param>boost.root=../../../.
<xml:param>html.stylesheet=../../../../doc/src/boostbook.css
;

View File

@@ -1,6 +1,6 @@
[library Boost.PFR
[quickbook 1.6]
[version 2.0]
[version 2.1]
[copyright 2016-2023 Antony Polukhin]
[category Language Features Emulation]
[license
@@ -17,6 +17,7 @@ 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]].
@@ -42,20 +43,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
@@ -80,20 +81,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
//
@@ -119,7 +120,7 @@ struct user_info {
std::string name, email, login;
};
/// Customizations via hand-written code or macro like BOOST_FUSION_ADAPT_STRUCT ///
/// Customizations via hand-written code ////////////////////////////////////////
auto db_api_tie(user_info& ui) noexcept {
return std::tie(ui.id, ui.name, ui.email, ui.login);
}
@@ -127,7 +128,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);
}
////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////
```
][
```
@@ -138,7 +139,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 //////////
@@ -146,14 +147,29 @@ 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 ]
@@ -164,7 +180,7 @@ Boost.PFR adds the following out-of-the-box functionality for aggregate initiali
* heterogeneous comparators
* hash
* IO streaming
* access to members by index
* access to members by index or type
* member type retrieval
* methods for cooperation with `std::tuple`
* methods to visit each field of the structure

View File

@@ -91,7 +91,7 @@ void test_examples() {
{
//[pfr_quick_examples_get
// Get field by index and assign new value to that field
// Get field by index/type and assign new value to that field
struct sample {
char c;
@@ -100,8 +100,9 @@ void test_examples() {
sample var{};
boost::pfr::get<1>(var) = 42.01f;
boost::pfr::get<char>(var) = 'A';
std::cout << var.f; // Outputs: 42.01
std::cout << var.c << var.f; // Outputs: A 42.01
//]
}

View File

@@ -30,20 +30,25 @@
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,6 +76,40 @@ constexpr auto get(T&& val, std::enable_if_t< std::is_rvalue_reference<T&&>::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) ));
}
/// \brief `tuple_element` has a member typedef `type` that returns the type of a field with index I in \aggregate T.
///
/// \b Example:

View File

@@ -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;

View File

@@ -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

View File

@@ -20,6 +20,8 @@ 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)
@@ -30,6 +32,16 @@ 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

View File

@@ -79,6 +79,45 @@ constexpr T&& get_impl(base_from_member<N, T>&& t) noexcept {
}
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 {
// 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<
detail::index_sequence_for<Values...>,

View File

@@ -19,8 +19,8 @@
namespace boost { namespace pfr {
/// 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.
/// 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.
///
/// \b Example:
/// \code
@@ -29,11 +29,9 @@ 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 has more priority than is_implicitly_reflectable,
/// because is_reflectable is more sharp than is_implicitly_reflectable
///
/// \note is_reflectable affects is_implicitly_reflectable, the decision made by is_reflectable is used by is_implicitly_reflectable.
template<class T, class WhatFor>
struct is_reflectable { /* do not has 'value' because value is unknown */ };
struct is_reflectable { /* does not have '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
@@ -46,17 +44,15 @@ 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 are disagree with is_implicitly_reflectable's default decision.
/// Specialize is_reflectable if you 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 are disagree with is_implicitly_reflectable_v's default decision.
/// Specialize is_reflectable if you 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

View File

@@ -0,0 +1,67 @@
// 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();
}

View File

@@ -6,6 +6,7 @@
// 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>