diff --git a/doc/Jamfile.v2 b/doc/Jamfile.v2 index 5fd85d4..e0bbe39 100644 --- a/doc/Jamfile.v2 +++ b/doc/Jamfile.v2 @@ -33,6 +33,8 @@ local doxygen_params = \"flattening{1}=\\xmlonly\\1\\endxmlonly\" \\ \"podops=\\b See \\b Also: \\xmlonlyThree ways of getting operators\\endxmlonly\" \\ \"constexprinit{1}=\\xmlonly\\1\\endxmlonly\" \\ + \"rcast=\\b Misc: Reinterpret casts unrelated types.\" \\ + \"rcast14=\\b Misc: Reinterpret casts unrelated types in C++14 only. May have overhead in C++14 only on non-optimizing compilers.\" \\ \"flatpod{1}=\\xmlonly\\1\\endxmlonly\" \\ " ; diff --git a/doc/pfr.qbk b/doc/pfr.qbk index cdc9814..b20e48f 100644 --- a/doc/pfr.qbk +++ b/doc/pfr.qbk @@ -23,7 +23,7 @@ This library provides tuple like methods for aggregate initializable structures, No macro or other type/member registrations required.] -Boost.Precise and Flat Reflection (Boost.PFR) adds following out-of-the-box functionality to PODs: +Boost.Precise and Flat Reflection (Boost.PFR) adds following out-of-the-box functionality for aggregate initializable structures: * comparison operators * heterogeneous comparators @@ -57,9 +57,9 @@ Precise functions have almost unlimited reflection capabilities, but may produce Here's how to chose your functions: +* If you work only with POD types and wish them flattened - use [*flat] functions * If you use C++17 - use [*precise] functions * If you work only with flat POD types in C++14 - use [*flat] functions -* If you work only with POD types in C++14 and wish them flattened - use [*flat] functions * If you have modern compiler in C++14 mode and work with non-POD literal types with some hierarchy - you are forced to use [*precise] functions [endsect] @@ -74,15 +74,15 @@ There are three ways to start using Boost.PFR hashing, comparison and streaming ][ Defines operators in global namespace ][ Defined operators could be found by ADL ][ Works for local types ][ Usable localy, without affecting code from other scopes ][ Ignores implicit conversion operators ][ Respects user defined operators ]] [[ - [headerref boost/pfr/flat/ops.hpp] + [headerref boost/pfr/precise/ops.hpp using\u00A0namespace\u00A0boost::pfr::ops;] - [headerref boost/pfr/precise/ops.hpp] + [headerref boost/pfr/flat/ops.hpp using\u00A0namespace\u00A0boost::pfr::flat_ops;] ][ no ][ no ][ yes ][ yes ][ no ][ yes ]] [[ - [headerref boost/pfr/flat/functions_for.hpp] + [macroref BOOST_PFR_FLAT_FUNCTIONS_FOR] - [headerref boost/pfr/precise/functions_for.hpp] + [macroref BOOST_PFR_PRECISE_FUNCTIONS_FOR] ][ yes if T is in it ][ yes ][ no ][ no, but could be limited to translation unit ][ yes for T ] [ no (compile time error) ]] [[ @@ -92,9 +92,9 @@ There are three ways to start using Boost.PFR hashing, comparison and streaming ][ yes ][ yes ][ yes ][ no, but could be limited to translation unit ][ yes all ][ yes ]] ] -More detailed description: +More detailed description follows: -[*1) [headerref boost/pfr/precise/ops.hpp] and [headerref boost/pfr/flat/ops.hpp] approach] +[*1. [headerref boost/pfr/precise/ops.hpp `using namespace boost::pfr::ops;`] and [headerref boost/pfr/flat/ops.hpp `using namespace boost::pfr::flat_ops;`] approach] This method is good if you're writing generic algorithms and need to use operators from Boost.PFR only if there's no operators defined for the type: @@ -123,7 +123,7 @@ struct uniform_comparator_less { }; ``` -[*2) [headerref boost/pfr/flat/functions_for.hpp] approach] +[*2. [macroref BOOST_PFR_FLAT_FUNCTIONS_FOR] and [macroref BOOST_PFR_PRECISE_FUNCTIONS_FOR] approach] This method is good if you're writing POD structure and wish to define operators for that structure. ``` @@ -156,7 +156,7 @@ struct empty { std::cout << empty{}; // Outputs `empty{}` if BOOST_PFR_FLAT_FUNCTIONS_FOR(empty) is commented out, '{}' otherwise. ``` -[*3) [headerref boost/pfr/flat/global_ops.hpp] approach] +[*3. [headerref boost/pfr/flat/global_ops.hpp] and [headerref boost/pfr/precise/global_ops.hpp] approach] This approach is for those, who wish to have comparisons/streaming/hashing for all their types. @@ -190,6 +190,26 @@ Following examples use definition from above: [table:quick_examples [[ Code snippet ] [ `var` content or output ] [ Function description: ]] [ + [ [pfr_quick_examples_flat_functors_uset] ] + [ `my_uset` constains `var` ] + [ + [classref boost::pfr::flat_hash] + + [classref boost::pfr::flat_equal_to] + ] +][ + [ [pfr_quick_examples_flat_functors_set] ] + [ `my_set` constains `var` ] + [ [classref boost::pfr::flat_less] ] +][ + [ [pfr_quick_examples_flat_ops] ] + [ assert succeeds ] + [ [headerref boost/pfr/flat/ops.hpp using\u00A0namespace\u00A0boost::pfr::flat_ops;] ] +][ + [ [pfr_quick_examples_ops] ] + [ assert succeeds ] + [ [headerref boost/pfr/precise/ops.hpp using\u00A0namespace\u00A0boost::pfr::ops;] ] +][ [ [pfr_quick_examples_flat_for_each] ] [ `var == {B, {778, 4.14159}}` ] [ [funcref boost::pfr::flat_for_each_field] ] diff --git a/example/examples.cpp b/example/examples.cpp index a38093c..fee997f 100644 --- a/example/examples.cpp +++ b/example/examples.cpp @@ -101,6 +101,9 @@ assert(r == 11); #include #include +#include +#include +#include namespace quick_examples_ns { @@ -131,6 +134,44 @@ void test_examples() { { bar var{'A', {777, 3.141593}}; +//[pfr_quick_examples_flat_functors_uset + // no `std::hash` or `bar::operator==(const bar&)` defined + std::unordered_set, boost::pfr::flat_equal_to<>> my_uset; + my_uset.insert(var); +//] + } + + { + bar var{'A', {777, 3.141593}}; + +//[pfr_quick_examples_flat_functors_set + // no `bar::operator<(const bar&)` defined + std::set> my_set; + my_set.insert(var); +//] + } + + { +//[pfr_quick_examples_flat_ops + using namespace boost::pfr::flat_ops; // Defines comparisons + assert((var < bar{'Z', {}} && var.f == foo{777, 3.141593})); +//] + std::cout << "boost::pfr::flat_structure_tie(var) :\n" << var << '\n'; + } + +#if __cplusplus >= 201606L /* Oulu meeting, not the exact value */ + { +//[pfr_quick_examples_ops + struct test { std::string f1; std::string_view f2; }; + using namespace boost::pfr::ops; // Defines comparisons + assert((test{"abc", ""} > test{"aaa", "zomg"})); +//] + } +#endif + + { + bar var{'A', {777, 3.141593}}; + //[pfr_quick_examples_flat_for_each // incrementing each field on 1: boost::pfr::flat_for_each_field(var, [](auto& field) { diff --git a/include/boost/pfr/flat/core.hpp b/include/boost/pfr/flat/core.hpp index 8937805..24f9ed7 100644 --- a/include/boost/pfr/flat/core.hpp +++ b/include/boost/pfr/flat/core.hpp @@ -23,6 +23,8 @@ namespace boost { namespace pfr { /// \brief Returns reference or const reference to a field with index `I` in \flattening{flattened} T. /// +/// \rcast +/// /// \b Example: /// \code /// struct my_struct { int i, short s; }; @@ -67,6 +69,8 @@ using flat_tuple_element_t = typename flat_tuple_element::type; /// \brief Creates an `std::tuple` from a \flattening{flattened} T. /// +/// \rcast +/// /// \b Example: /// \code /// struct my_struct { int i, short s; }; @@ -85,6 +89,8 @@ auto flat_structure_to_tuple(const T& val) noexcept { /// \brief Creates an `std::tuple` with lvalue references to fields of a \flattening{flattened} T. /// +/// \rcast +/// /// \b Requires: `T` must not have const fields. /// /// \b Example: @@ -104,10 +110,12 @@ auto flat_structure_tie(T& val /* @cond */, std::enable_if_t< std::is_trivially_ /// Calls `func` for each field of a \flattening{flattened} POD `value`. /// +/// \rcast +/// /// \param func must have one of the following signatures: -/// * template any_return_type func(U&& field) // field of value is perfect forwarded to function -/// * template any_return_type func(U&& field, std::size_t i) -/// * template any_return_type func(U&& value, I i) // Here I is an `std::integral_constant` +/// * any_return_type func(U&& field) // field of value is perfect forwarded to function +/// * any_return_type func(U&& field, std::size_t i) +/// * any_return_type func(U&& value, I i) // Here I is an `std::integral_constant` /// /// \param value After \flattening{flattening} to each field of this variable will be the `func` applied. /// diff --git a/include/boost/pfr/flat/functions_for.hpp b/include/boost/pfr/flat/functions_for.hpp index cb472de..a9bcda9 100644 --- a/include/boost/pfr/flat/functions_for.hpp +++ b/include/boost/pfr/flat/functions_for.hpp @@ -33,6 +33,8 @@ /// std::cout << s1 << std::endl; // Outputs: {0, 1, H, e, l, l, o, , , 0, 6, 7, 8, 9, 10, 11} /// \endcode /// +/// \rcast +/// /// \podops for other ways to define operators and more details. /// /// \b Defines \b following \b for \b T: diff --git a/include/boost/pfr/flat/functors.hpp b/include/boost/pfr/flat/functors.hpp index 62bc827..222de6b 100644 --- a/include/boost/pfr/flat/functors.hpp +++ b/include/boost/pfr/flat/functors.hpp @@ -18,13 +18,17 @@ /// \file boost/pfr/functors.hpp /// Contains functors that can work with PODs and are close to the Standard Library ones. /// Each functor \flattening{flattens} the POD type and iterates over its fields. +/// +/// \rcast namespace boost { namespace pfr { ///////////////////// Comparisons /// \brief std::equal_to like flattening comparator template struct flat_equal_to { - /// \return \b true if each field of \b x equals the field with same index of \b y + /// \return \b true if each field of \b x equals the field with same index of \b y. + /// + /// \rcast bool operator()(const T& x, const T& y) const noexcept { return detail::equal_impl<0, flat_tuple_size_v >::cmp(detail::tie_as_flat_tuple(x), detail::tie_as_flat_tuple(y)); } @@ -54,7 +58,9 @@ template <> struct flat_equal_to { /// \brief std::not_equal like flattening comparator template struct flat_not_equal { - /// \return \b true if at least one field \b x not equals the field with same index of \b y + /// \return \b true if at least one field \b x not equals the field with same index of \b y. + /// + /// \rcast bool operator()(const T& x, const T& y) const noexcept { return detail::not_equal_impl<0, flat_tuple_size_v >::cmp(detail::tie_as_flat_tuple(x), detail::tie_as_flat_tuple(y)); } @@ -82,7 +88,9 @@ template <> struct flat_not_equal { /// \brief std::greater like flattening comparator template struct flat_greater { - /// \return \b true if field of \b x greater than the field with same index of \b y and all previous fields of \b x equal to the same fields of \b y + /// \return \b true if field of \b x greater than the field with same index of \b y and all previous fields of \b x equal to the same fields of \b y. + /// + /// \rcast bool operator()(const T& x, const T& y) const noexcept { return detail::greater_impl<0, flat_tuple_size_v >::cmp(detail::tie_as_flat_tuple(x), detail::tie_as_flat_tuple(y)); } @@ -113,7 +121,9 @@ template <> struct flat_greater { /// \brief std::less like flattening comparator template struct flat_less { - /// \return \b true if field of \b x less than the field with same index of \b y and all previous fields of \b x equal to the same fields of \b y + /// \return \b true if field of \b x less than the field with same index of \b y and all previous fields of \b x equal to the same fields of \b y. + /// + /// \rcast bool operator()(const T& x, const T& y) const noexcept { return detail::less_impl<0, flat_tuple_size_v >::cmp(detail::tie_as_flat_tuple(x), detail::tie_as_flat_tuple(y)); } @@ -145,7 +155,9 @@ template <> struct flat_less { /// \brief std::greater_equal like flattening comparator template struct flat_greater_equal { /// \return \b true if field of \b x greater than the field with same index of \b y and all previous fields of \b x equal to the same fields of \b y; - /// or if each field of \b x equals the field with same index of \b y . + /// or if each field of \b x equals the field with same index of \b y. + /// + /// \rcast bool operator()(const T& x, const T& y) const noexcept { return detail::greater_equal_impl<0, flat_tuple_size_v >::cmp(detail::tie_as_flat_tuple(x), detail::tie_as_flat_tuple(y)); } @@ -177,7 +189,9 @@ template <> struct flat_greater_equal { /// \brief std::less_equal like flattening comparator template struct flat_less_equal { /// \return \b true if field of \b x less than the field with same index of \b y and all previous fields of \b x equal to the same fields of \b y; - /// or if each field of \b x equals the field with same index of \b y . + /// or if each field of \b x equals the field with same index of \b y. + /// + /// \rcast bool operator()(const T& x, const T& y) const noexcept { return detail::less_equal_impl<0, flat_tuple_size_v >::cmp(detail::tie_as_flat_tuple(x), detail::tie_as_flat_tuple(y)); } @@ -209,7 +223,9 @@ template <> struct flat_less_equal { /// \brief std::hash like flattening functor template struct flat_hash { - /// \return hash value of \b x + /// \return hash value of \b x. + /// + /// \rcast std::size_t operator()(const T& x) const noexcept { return detail::hash_impl<0, flat_tuple_size_v >::compute(detail::tie_as_flat_tuple(x)); } diff --git a/include/boost/pfr/flat/global_ops.hpp b/include/boost/pfr/flat/global_ops.hpp index f2c62ca..54e7b35 100644 --- a/include/boost/pfr/flat/global_ops.hpp +++ b/include/boost/pfr/flat/global_ops.hpp @@ -32,6 +32,8 @@ /// std::cout << s1 << std::endl; // Outputs: {0, 1, H, e, l, l, o, , , 0, 6, 7, 8, 9, 10, 11} /// \endcode /// +/// \rcast +/// /// \podops for other ways to define operators and more details. /// /// \b This \b header \b defines: diff --git a/include/boost/pfr/flat/io.hpp b/include/boost/pfr/flat/io.hpp index b2c0828..d9b0ea4 100644 --- a/include/boost/pfr/flat/io.hpp +++ b/include/boost/pfr/flat/io.hpp @@ -22,6 +22,8 @@ namespace boost { namespace pfr { /// \brief Writes \flattening{flattened} POD `value` to `out` /// +/// \rcast14 +/// /// \b Example: /// \code /// struct my_struct { int i, short s; }; @@ -37,6 +39,8 @@ void flat_write(std::basic_ostream& out, const T& value) { /// Reads \flattening{flattened} POD `value` from stream `in` /// +/// \rcast14 +/// /// \b Example: /// \code /// struct my_struct { int i, short s; }; diff --git a/include/boost/pfr/flat/ops.hpp b/include/boost/pfr/flat/ops.hpp index ad3265c..0affc2b 100644 --- a/include/boost/pfr/flat/ops.hpp +++ b/include/boost/pfr/flat/ops.hpp @@ -36,6 +36,8 @@ /// std::cout << s1 << std::endl; // Outputs: {0, 1, H, e, l, l, o, , , 0, 6, 7, 8, 9, 10, 11} /// \endcode /// +/// \rcast +/// /// \podops for other ways to define operators and more details. /// /// \b This \b header \b contains: diff --git a/include/boost/pfr/precise/core.hpp b/include/boost/pfr/precise/core.hpp index 12f3b28..fa3e218 100644 --- a/include/boost/pfr/precise/core.hpp +++ b/include/boost/pfr/precise/core.hpp @@ -26,6 +26,8 @@ namespace boost { namespace pfr { /// /// \b Requires: C++17 or \flatpod{C++14 flat POD}. /// +/// \rcast14 +/// /// \b Example: /// \code /// struct my_struct { int i, short s; }; @@ -74,6 +76,8 @@ using tuple_element_t = typename tuple_element::type; /// /// \b Requires: C++17 or \flatpod{C++14 flat POD}. /// +/// \rcast14 +/// /// \b Example: /// \code /// struct my_struct { int i, short s; }; @@ -96,6 +100,8 @@ constexpr auto structure_to_tuple(const T& val) noexcept { /// /// \b Requires: C++17 or \flatpod{C++14 flat POD}. /// +/// \rcast14 +/// /// \b Example: /// \code /// struct my_struct { int i, short s; }; @@ -118,12 +124,14 @@ constexpr auto structure_tie(T& val) noexcept { /// \b Requires: C++17 or \constexprinit{C++14 constexpr aggregate intializable type}. /// /// \param func must have one of the following signatures: -/// * template any_return_type func(U&& field) // field of value is perfect forwarded to function -/// * template any_return_type func(U&& field, std::size_t i) -/// * template any_return_type func(U&& value, I i) // Here I is an `std::integral_constant` +/// * any_return_type func(U&& field) // field of value is perfect forwarded to function +/// * any_return_type func(U&& field, std::size_t i) +/// * any_return_type func(U&& value, I i) // Here I is an `std::integral_constant` /// /// \param value To each field of this variable will be the `func` applied. /// +/// \rcast14 +/// /// \b Example: /// \code /// struct my_struct { int i, short s; }; diff --git a/include/boost/pfr/precise/functions_for.hpp b/include/boost/pfr/precise/functions_for.hpp index f1de098..19779a7 100644 --- a/include/boost/pfr/precise/functions_for.hpp +++ b/include/boost/pfr/precise/functions_for.hpp @@ -33,6 +33,8 @@ /// std::cout << s1 << std::endl; // Outputs: {0, 1, H, e, l, l, o, , , 0, 6, 7, 8, 9, 10, 11} /// \endcode /// +/// \rcast14 +/// /// \podops for other ways to define operators and more details. /// /// \b Defines \b following \b for \b T: diff --git a/include/boost/pfr/precise/functors.hpp b/include/boost/pfr/precise/functors.hpp index bc00e15..09aa7f9 100644 --- a/include/boost/pfr/precise/functors.hpp +++ b/include/boost/pfr/precise/functors.hpp @@ -20,6 +20,8 @@ /// Each functor iterates over fields of the type. /// /// \b Requires: C++17 or \constexprinit{C++14 constexpr aggregate intializable type}. +/// +/// \rcast14 namespace boost { namespace pfr { namespace detail { @@ -59,7 +61,9 @@ namespace detail { /// \brief std::equal_to like comparator template struct equal_to { - /// \return \b true if each field of \b x equals the field with same index of \b y + /// \return \b true if each field of \b x equals the field with same index of \b y. + /// + /// \rcast14 bool operator()(const T& x, const T& y) const { return detail::binary_visit(x, y); } @@ -86,7 +90,9 @@ template <> struct equal_to { /// \brief std::not_equal like comparator template struct not_equal { - /// \return \b true if at least one field \b x not equals the field with same index of \b y + /// \return \b true if at least one field \b x not equals the field with same index of \b y. + /// + /// \rcast14 bool operator()(const T& x, const T& y) const { return detail::binary_visit(x, y); } @@ -114,7 +120,9 @@ template <> struct not_equal { /// \brief std::greater like comparator template struct greater { - /// \return \b true if field of \b x greater than the field with same index of \b y and all previous fields of \b x equal to the same fields of \b y + /// \return \b true if field of \b x greater than the field with same index of \b y and all previous fields of \b x equal to the same fields of \b y. + /// + /// \rcast14 bool operator()(const T& x, const T& y) const { return detail::binary_visit(x, y); } @@ -142,7 +150,9 @@ template <> struct greater { /// \brief std::less like comparator template struct less { - /// \return \b true if field of \b x less than the field with same index of \b y and all previous fields of \b x equal to the same fields of \b y + /// \return \b true if field of \b x less than the field with same index of \b y and all previous fields of \b x equal to the same fields of \b y. + /// + /// \rcast14 bool operator()(const T& x, const T& y) const { return detail::binary_visit(x, y); } @@ -171,7 +181,9 @@ template <> struct less { /// \brief std::greater_equal like comparator template struct greater_equal { /// \return \b true if field of \b x greater than the field with same index of \b y and all previous fields of \b x equal to the same fields of \b y; - /// or if each field of \b x equals the field with same index of \b y . + /// or if each field of \b x equals the field with same index of \b y. + /// + /// \rcast14 bool operator()(const T& x, const T& y) const { return detail::binary_visit(x, y); } @@ -200,7 +212,9 @@ template <> struct greater_equal { /// \brief std::less_equal like comparator template struct less_equal { /// \return \b true if field of \b x less than the field with same index of \b y and all previous fields of \b x equal to the same fields of \b y; - /// or if each field of \b x equals the field with same index of \b y . + /// or if each field of \b x equals the field with same index of \b y. + /// + /// \rcast14 bool operator()(const T& x, const T& y) const { return detail::binary_visit(x, y); } @@ -229,7 +243,9 @@ template <> struct less_equal { /// \brief std::hash like functor template struct hash { - /// \return hash value of \b x + /// \return hash value of \b x. + /// + /// \rcast14 std::size_t operator()(const T& x) const { constexpr std::size_t fields_count = detail::fields_count>(); #if __cplusplus >= 201606L /* Oulu meeting, not the exact value */ diff --git a/include/boost/pfr/precise/global_ops.hpp b/include/boost/pfr/precise/global_ops.hpp index e3a7aad..fca1c44 100644 --- a/include/boost/pfr/precise/global_ops.hpp +++ b/include/boost/pfr/precise/global_ops.hpp @@ -32,6 +32,8 @@ /// std::cout << s1 << std::endl; // Outputs: {0, 1, H, e, l, l, o, , , 0, 6, 7, 8, 9, 10, 11} /// \endcode /// +/// \rcast14 +/// /// \podops for other ways to define operators and more details. /// /// \b This \b header \b defines: diff --git a/include/boost/pfr/precise/io.hpp b/include/boost/pfr/precise/io.hpp index f638dc5..cf2a0b1 100644 --- a/include/boost/pfr/precise/io.hpp +++ b/include/boost/pfr/precise/io.hpp @@ -26,6 +26,8 @@ namespace boost { namespace pfr { /// /// \b Requires: C++17 or \constexprinit{C++14 constexpr aggregate intializable type}. /// +/// \rcast14 +/// /// \b Example: /// \code /// struct my_struct { int i, short s; }; @@ -54,6 +56,8 @@ void write(std::basic_ostream& out, const T& value) { /// /// \b Requires: C++17 or \constexprinit{C++14 constexpr aggregate intializable type}. /// +/// \rcast14 +/// /// \b Example: /// \code /// struct my_struct { int i, short s; }; diff --git a/include/boost/pfr/precise/ops.hpp b/include/boost/pfr/precise/ops.hpp index f2979cb..c399e85 100644 --- a/include/boost/pfr/precise/ops.hpp +++ b/include/boost/pfr/precise/ops.hpp @@ -23,6 +23,8 @@ /// /// \b Requires: C++17 or \constexprinit{C++14 constexpr aggregate intializable type}. /// +/// \rcast14 +/// /// \b Example: /// \code /// #include