From a70d02103a5101719edd26e11bcd4b2eb5b963cd Mon Sep 17 00:00:00 2001 From: denzor200 Date: Sun, 27 Nov 2022 19:48:32 +0400 Subject: [PATCH 01/11] Add is_implicitly_reflectable trait --- README.md | 44 ++++++++++++ doc/pfr.qbk | 1 + include/boost/pfr.hpp | 2 + .../boost/pfr/detail/possible_reflectable.hpp | 32 +++++++++ include/boost/pfr/traits.hpp | 72 +++++++++++++++++++ include/boost/pfr/traits_fwd.hpp | 19 +++++ 6 files changed, 170 insertions(+) mode change 100644 => 100755 README.md mode change 100644 => 100755 doc/pfr.qbk mode change 100644 => 100755 include/boost/pfr.hpp create mode 100755 include/boost/pfr/detail/possible_reflectable.hpp create mode 100755 include/boost/pfr/traits.hpp create mode 100755 include/boost/pfr/traits_fwd.hpp diff --git a/README.md b/README.md old mode 100644 new mode 100755 index f827167..d97f4ad --- a/README.md +++ b/README.md @@ -94,6 +94,50 @@ Outputs: my_struct has 2 fields: {"Das ist fantastisch!", 100} ``` +### Motivating Example #3 + +```c++ +#include +#include +#include +#include +#include +#include "boost/pfr/io.hpp" +namespace x3 = boost::spirit::x3; +struct ast_employee { // No BOOST_FUSION_ADAPT_STRUCT defined + int age; + std::string forename; + std::string surname; + double salary; +}; +auto const quoted_string = x3::lexeme['"' >> +(x3::ascii::char_ - '"') >> '"']; +x3::rule const employee = "employee"; +auto const employee_def = + x3::lit("employee") + >> '{' + >> x3::int_ >> ',' + >> quoted_string >> ',' + >> quoted_string >> ',' + >> x3::double_ + >> '}' + ; +BOOST_SPIRIT_DEFINE(employee); +int main() { + std::string str = R"(employee{34, "Chip", "Douglas", 2500.00})"; + ast_employee emp; + x3::phrase_parse(str.begin(), + str.end(), + employee, + x3::ascii::space, + emp); + std::cout << boost::pfr::io(emp) << std::endl; +} +``` +Outputs: +``` +(34 Chip Douglas 2500) +``` + ### Requirements and Limitations diff --git a/doc/pfr.qbk b/doc/pfr.qbk old mode 100644 new mode 100755 index e1bceef..151c615 --- a/doc/pfr.qbk +++ b/doc/pfr.qbk @@ -168,6 +168,7 @@ Boost.PFR adds the following out-of-the-box functionality for aggregate initiali * member type retrieval * methods for cooperation with `std::tuple` * methods to visit each field of the structure +* trait to detect potential ability to reflect type, and ability to override trait's decision in user-side code Boost.PFR is a header only library that does not depend on Boost. You can just copy the content of the "include" folder [@https://github.com/boostorg/pfr from the Boost.PFR github] into your project, and the library will work fine. For a version of the library without `boost::` namespace see [@https://github.com/apolukhin/pfr_non_boost PFR]. diff --git a/include/boost/pfr.hpp b/include/boost/pfr.hpp old mode 100644 new mode 100755 index 32ff067..699e931 --- a/include/boost/pfr.hpp +++ b/include/boost/pfr.hpp @@ -17,5 +17,7 @@ #include #include #include +#include +#include #endif // BOOST_PFR_HPP diff --git a/include/boost/pfr/detail/possible_reflectable.hpp b/include/boost/pfr/detail/possible_reflectable.hpp new file mode 100755 index 0000000..395f9f6 --- /dev/null +++ b/include/boost/pfr/detail/possible_reflectable.hpp @@ -0,0 +1,32 @@ +// Copyright (c) 2022 Denis Mikhailov +// +// 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) + +#ifndef BOOST_PFR_DETAIL_POSSIBLE_REFLECTABLE_HPP +#define BOOST_PFR_DETAIL_POSSIBLE_REFLECTABLE_HPP +#pragma once + +#include +#include + +#include // for std::is_aggregate + +namespace boost { namespace pfr { namespace detail { + +///////////////////// Returns false when the type exactly wasn't be reflectable +template +constexpr decltype(is_reflectable::value) possible_reflectable(long) noexcept { + return is_reflectable::value; +} + +template +constexpr bool possible_reflectable(int) noexcept { + using type = std::remove_cv_t; + // TODO: it should work in C++14 + return std::is_aggregate(); +} + +}}} + +#endif // BOOST_PFR_DETAIL_POSSIBLE_REFLECTABLE_HPP \ No newline at end of file diff --git a/include/boost/pfr/traits.hpp b/include/boost/pfr/traits.hpp new file mode 100755 index 0000000..5b64bee --- /dev/null +++ b/include/boost/pfr/traits.hpp @@ -0,0 +1,72 @@ +// Copyright (c) 2022 Denis Mikhailov +// +// 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) + +#ifndef BOOST_PFR_TRAITS_HPP +#define BOOST_PFR_TRAITS_HPP +#pragma once + +#include + +#include +#include + +/// \file boost/pfr/traits.hpp +/// Contains traits \forcedlink{is_reflectable} and \forcedlink{is_implicitly_reflectable} for detecting an ability to reflect type. +/// +/// \b Synopsis: + +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 CAN(and in some difficult cases - SHOULD) specialize is_reflectable on his own. +/// +/// \b Example: +/// \code +/// namespace boost { namespace pfr { +/// template struct is_reflectable : std::false_type {}; // 'A' won't be interpreted as reflectable everywhere +/// template<> struct is_reflectable : 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 +/// +/// \customadaptor using is_reflectable trait and so others. +template +struct is_reflectable { /* do not has 'value' because value is unknown */ }; + +// TODO: need tests to show that these specs are sfinae-friendly +template +struct is_reflectable : std::integral_constant< bool, boost::pfr::is_reflectable::value > {}; + +template +struct is_reflectable : std::integral_constant< bool, boost::pfr::is_reflectable::value > {}; + +template +struct is_reflectable : std::integral_constant< bool, boost::pfr::is_reflectable::value > {}; + +/// Checks the input type for the potential to be reflected. +/// Use is_reflectable specializations if you are disagree with is_implicitly_reflectable's default decision. +template +using is_implicitly_reflectable = std::integral_constant< bool, boost::pfr::detail::possible_reflectable(1L) >; + + +/// `is_reflectable_v` is a template variable that valid when it known that type T can or can't be reflected using Boost.PFR. +/// +/// \b Example: +/// \code +/// template>* = nullptr> +/// T tag_invoke(boost::json::value_to_tag, const boost::json::value& jv); // overload for definitely reflectable type +/// \endcode +template +constexpr bool is_reflectable_v = is_reflectable::value; + +/// Checks the input type for the potential to be reflected. +/// Use is_reflectable specializations if you are disagree with is_implicitly_reflectable_v's default decision. +template +constexpr bool is_implicitly_reflectable_v = is_implicitly_reflectable::value; + +}} // namespace boost::pfr + +#endif // BOOST_PFR_TRAITS_HPP diff --git a/include/boost/pfr/traits_fwd.hpp b/include/boost/pfr/traits_fwd.hpp new file mode 100755 index 0000000..319f082 --- /dev/null +++ b/include/boost/pfr/traits_fwd.hpp @@ -0,0 +1,19 @@ +// Copyright (c) 2022 Denis Mikhailov +// +// 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) + +#ifndef BOOST_PFR_DETAIL_TRAITS_FWD_HPP +#define BOOST_PFR_DETAIL_TRAITS_FWD_HPP +#pragma once + +#include + +namespace boost { namespace pfr { + +template +struct is_reflectable; + +}} + +#endif // BOOST_PFR_DETAIL_TRAITS_FWD_HPP \ No newline at end of file From 7a3a419c355a59c3b45f672cee0f80a63cee532a Mon Sep 17 00:00:00 2001 From: denzor200 Date: Sun, 27 Nov 2022 19:52:57 +0400 Subject: [PATCH 02/11] identations in Motivating Example --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index d97f4ad..d562fbf 100755 --- a/README.md +++ b/README.md @@ -99,18 +99,24 @@ my_struct has 2 fields: {"Das ist fantastisch!", 100} ```c++ #include #include + #include #include #include + #include "boost/pfr/io.hpp" + namespace x3 = boost::spirit::x3; + struct ast_employee { // No BOOST_FUSION_ADAPT_STRUCT defined int age; std::string forename; std::string surname; double salary; }; + auto const quoted_string = x3::lexeme['"' >> +(x3::ascii::char_ - '"') >> '"']; + x3::rule const employee = "employee"; auto const employee_def = x3::lit("employee") @@ -122,6 +128,7 @@ auto const employee_def = >> '}' ; BOOST_SPIRIT_DEFINE(employee); + int main() { std::string str = R"(employee{34, "Chip", "Douglas", 2500.00})"; ast_employee emp; @@ -132,6 +139,7 @@ int main() { emp); std::cout << boost::pfr::io(emp) << std::endl; } + ``` Outputs: ``` From ba40d86097566afbe8e9c9763f0ebdfeb60143ab Mon Sep 17 00:00:00 2001 From: Denis Mikhaylov Date: Thu, 1 Dec 2022 14:09:37 +0600 Subject: [PATCH 03/11] Add static test to detect ability to integrate PFR as fallback into the Fusion --- test/Jamfile.v2 | 2 ++ test/can_be_as_fallback_in_the_fusion.cpp | 33 +++++++++++++++++++++++ 2 files changed, 35 insertions(+) mode change 100644 => 100755 test/Jamfile.v2 create mode 100755 test/can_be_as_fallback_in_the_fusion.cpp diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 old mode 100644 new mode 100755 index 21ff053..b1e1558 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -53,6 +53,8 @@ test-suite pfr_tests [ run offset_based_getter.cpp ] + [ run can_be_as_fallback_in_the_fusion.cpp ] + [ run test_tuple_sizes_on.cpp : : : BOOST_PFR_RUN_TEST_ON=char : test_tuple_sizes_on_chars ] [ run test_tuple_sizes_on.cpp : : : BOOST_PFR_RUN_TEST_ON=int : test_tuple_sizes_on_ints ] [ run test_tuple_sizes_on.cpp : : : BOOST_PFR_RUN_TEST_ON=short : test_tuple_sizes_on_shorts ] diff --git a/test/can_be_as_fallback_in_the_fusion.cpp b/test/can_be_as_fallback_in_the_fusion.cpp new file mode 100755 index 0000000..545b414 --- /dev/null +++ b/test/can_be_as_fallback_in_the_fusion.cpp @@ -0,0 +1,33 @@ +// Copyright (c) 2022 Denis Mikhailov +// +// 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 +#include + +struct Aggregate {}; +using NonAggregate = int; + +namespace boost { namespace pfr { + struct boost_fusion_tag; +}} + +template +struct tag_of_fallback : std::false_type { +}; + +template +struct tag_of_fallback::value>> +{ + using type = std::conditional_t< + boost::pfr::is_implicitly_reflectable::value + , std::true_type + , std::false_type + >; +}; + +static_assert(tag_of_fallback::type{} == true, ""); +static_assert(tag_of_fallback::type{} == false, ""); + +int main() { } From aa5abd8d763eb4b3761131cb97bee4c6076ac0fb Mon Sep 17 00:00:00 2001 From: Denis Mikhaylov Date: Thu, 1 Dec 2022 16:11:45 +0600 Subject: [PATCH 04/11] Fixed C++14 build --- .../boost/pfr/detail/possible_reflectable.hpp | 4 ++++ test/can_be_as_fallback_in_the_fusion.cpp | 20 +++++++++++-------- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/include/boost/pfr/detail/possible_reflectable.hpp b/include/boost/pfr/detail/possible_reflectable.hpp index 395f9f6..e347a97 100755 --- a/include/boost/pfr/detail/possible_reflectable.hpp +++ b/include/boost/pfr/detail/possible_reflectable.hpp @@ -24,7 +24,11 @@ template constexpr bool possible_reflectable(int) noexcept { using type = std::remove_cv_t; // TODO: it should work in C++14 +# if defined(__cpp_lib_is_aggregate) return std::is_aggregate(); +# else + return true; +# endif } }}} diff --git a/test/can_be_as_fallback_in_the_fusion.cpp b/test/can_be_as_fallback_in_the_fusion.cpp index 545b414..d9e5376 100755 --- a/test/can_be_as_fallback_in_the_fusion.cpp +++ b/test/can_be_as_fallback_in_the_fusion.cpp @@ -4,30 +4,34 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #include -#include struct Aggregate {}; using NonAggregate = int; -namespace boost { namespace pfr { - struct boost_fusion_tag; -}} +template +struct is_implicitly_reflectable : std::false_type +{}; + +template<> +struct is_implicitly_reflectable : std::true_type +{}; template -struct tag_of_fallback : std::false_type { +struct tag_of_fallback { + using type = int; // unknown }; template struct tag_of_fallback::value>> { using type = std::conditional_t< - boost::pfr::is_implicitly_reflectable::value + is_implicitly_reflectable::value , std::true_type , std::false_type >; }; -static_assert(tag_of_fallback::type{} == true, ""); -static_assert(tag_of_fallback::type{} == false, ""); +static_assert(tag_of_fallback::type::value == true, ""); +static_assert(tag_of_fallback::type::value == false, ""); int main() { } From 6f853dad2c33ce993321544524bc71725ac3d335 Mon Sep 17 00:00:00 2001 From: Denis Mikhaylov Date: Thu, 1 Dec 2022 17:13:06 +0600 Subject: [PATCH 05/11] Fixed inspect issues --- include/boost/pfr/detail/possible_reflectable.hpp | 4 +++- include/boost/pfr/traits.hpp | 1 + include/boost/pfr/traits_fwd.hpp | 4 +++- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/include/boost/pfr/detail/possible_reflectable.hpp b/include/boost/pfr/detail/possible_reflectable.hpp index e347a97..45fd25d 100755 --- a/include/boost/pfr/detail/possible_reflectable.hpp +++ b/include/boost/pfr/detail/possible_reflectable.hpp @@ -33,4 +33,6 @@ constexpr bool possible_reflectable(int) noexcept { }}} -#endif // BOOST_PFR_DETAIL_POSSIBLE_REFLECTABLE_HPP \ No newline at end of file +#endif // BOOST_PFR_DETAIL_POSSIBLE_REFLECTABLE_HPP + + diff --git a/include/boost/pfr/traits.hpp b/include/boost/pfr/traits.hpp index 5b64bee..946a219 100755 --- a/include/boost/pfr/traits.hpp +++ b/include/boost/pfr/traits.hpp @@ -70,3 +70,4 @@ constexpr bool is_implicitly_reflectable_v = is_implicitly_reflectable Date: Thu, 1 Dec 2022 17:27:13 +0600 Subject: [PATCH 06/11] Fix strip_boost_namespace's issues --- include/boost/pfr/detail/possible_reflectable.hpp | 2 +- include/boost/pfr/traits_fwd.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/boost/pfr/detail/possible_reflectable.hpp b/include/boost/pfr/detail/possible_reflectable.hpp index 45fd25d..ef27dd3 100755 --- a/include/boost/pfr/detail/possible_reflectable.hpp +++ b/include/boost/pfr/detail/possible_reflectable.hpp @@ -31,7 +31,7 @@ constexpr bool possible_reflectable(int) noexcept { # endif } -}}} +}}} // namespace boost::pfr::detail #endif // BOOST_PFR_DETAIL_POSSIBLE_REFLECTABLE_HPP diff --git a/include/boost/pfr/traits_fwd.hpp b/include/boost/pfr/traits_fwd.hpp index 1e7fb53..c015e9d 100755 --- a/include/boost/pfr/traits_fwd.hpp +++ b/include/boost/pfr/traits_fwd.hpp @@ -14,7 +14,7 @@ namespace boost { namespace pfr { template struct is_reflectable; -}} +}} // namespace boost::pfr #endif // BOOST_PFR_DETAIL_TRAITS_FWD_HPP From 968d692c5ec7c0ae0a3cefdf44d5e67382c00c6c Mon Sep 17 00:00:00 2001 From: Denis Mikhaylov Date: Thu, 1 Dec 2022 17:42:09 +0600 Subject: [PATCH 07/11] permissions restored --- README.md | 0 doc/pfr.qbk | 0 include/boost/pfr.hpp | 0 include/boost/pfr/detail/possible_reflectable.hpp | 0 include/boost/pfr/traits.hpp | 0 include/boost/pfr/traits_fwd.hpp | 0 test/Jamfile.v2 | 0 test/can_be_as_fallback_in_the_fusion.cpp | 0 8 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 README.md mode change 100755 => 100644 doc/pfr.qbk mode change 100755 => 100644 include/boost/pfr.hpp mode change 100755 => 100644 include/boost/pfr/detail/possible_reflectable.hpp mode change 100755 => 100644 include/boost/pfr/traits.hpp mode change 100755 => 100644 include/boost/pfr/traits_fwd.hpp mode change 100755 => 100644 test/Jamfile.v2 mode change 100755 => 100644 test/can_be_as_fallback_in_the_fusion.cpp diff --git a/README.md b/README.md old mode 100755 new mode 100644 diff --git a/doc/pfr.qbk b/doc/pfr.qbk old mode 100755 new mode 100644 diff --git a/include/boost/pfr.hpp b/include/boost/pfr.hpp old mode 100755 new mode 100644 diff --git a/include/boost/pfr/detail/possible_reflectable.hpp b/include/boost/pfr/detail/possible_reflectable.hpp old mode 100755 new mode 100644 diff --git a/include/boost/pfr/traits.hpp b/include/boost/pfr/traits.hpp old mode 100755 new mode 100644 diff --git a/include/boost/pfr/traits_fwd.hpp b/include/boost/pfr/traits_fwd.hpp old mode 100755 new mode 100644 diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 old mode 100755 new mode 100644 diff --git a/test/can_be_as_fallback_in_the_fusion.cpp b/test/can_be_as_fallback_in_the_fusion.cpp old mode 100755 new mode 100644 From b2acaacaaf2552ead64b235e6b4de26e51768551 Mon Sep 17 00:00:00 2001 From: denzor200 Date: Fri, 2 Dec 2022 18:05:52 +0400 Subject: [PATCH 08/11] Ability to disable implicitly reflection using the macro --- doc/pfr.qbk | 1 + include/boost/pfr/detail/config.hpp | 9 +++++++++ include/boost/pfr/detail/possible_reflectable.hpp | 3 +-- include/boost/pfr/traits.hpp | 5 ++++- test/print_config.cpp | 1 + 5 files changed, 16 insertions(+), 3 deletions(-) diff --git a/doc/pfr.qbk b/doc/pfr.qbk index 151c615..04634fb 100644 --- a/doc/pfr.qbk +++ b/doc/pfr.qbk @@ -468,6 +468,7 @@ By default Boost.PFR [*auto-detects your compiler abilities] and automatically d [[*BOOST_PFR_USE_LOOPHOLE*] [Define to `1` if you wish to override Boost.PFR choice and exploit [@http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2118 CWG 2118] for reflection. Define to `0` to override Boost.PFR choice and disable CWG 2118 usage.]] [[*BOOST_PFR_USE_STD_MAKE_INTEGRAL_SEQUENCE*] [Define to `0` if you are hit by the template instantiation depth issues with `std::make_integer_sequence` and wish to use Boost.PFR version of that metafunction. Define to `1` to override Boost.PFR detection logic. ]] [[*BOOST_PFR_HAS_GUARANTEED_COPY_ELISION*] [Define to `0` if your compiler does not implement C++17 guaranteed copy elision properly and fails to reflect aggregates with non-movable fields. Define to `1` to override Boost.PFR detection logic. ]] + [[*BOOST_PFR_ENABLE_IMPLICITLY_REFLECTION*] [Define to `0` if you are hit by lots of non-effective choices made by implicitly reflection. Define to `1` to override Boost.PFR detection logic. ]] ] diff --git a/include/boost/pfr/detail/config.hpp b/include/boost/pfr/detail/config.hpp index 8a1ac7d..64a8f97 100644 --- a/include/boost/pfr/detail/config.hpp +++ b/include/boost/pfr/detail/config.hpp @@ -77,6 +77,15 @@ # endif #endif +#ifndef BOOST_PFR_ENABLE_IMPLICITLY_REFLECTION +# if defined(__cpp_lib_is_aggregate) +# define BOOST_PFR_ENABLE_IMPLICITLY_REFLECTION 1 +# else +// There is no way to detect potential ability to be reflectable without std::is_aggregare +# define BOOST_PFR_ENABLE_IMPLICITLY_REFLECTION 0 +# endif +#endif + #if defined(__has_cpp_attribute) # if __has_cpp_attribute(maybe_unused) # define BOOST_PFR_MAYBE_UNUSED [[maybe_unused]] diff --git a/include/boost/pfr/detail/possible_reflectable.hpp b/include/boost/pfr/detail/possible_reflectable.hpp index ef27dd3..069fafd 100644 --- a/include/boost/pfr/detail/possible_reflectable.hpp +++ b/include/boost/pfr/detail/possible_reflectable.hpp @@ -22,9 +22,8 @@ constexpr decltype(is_reflectable::value) possible_reflectable(long) template constexpr bool possible_reflectable(int) noexcept { - using type = std::remove_cv_t; - // TODO: it should work in C++14 # if defined(__cpp_lib_is_aggregate) + using type = std::remove_cv_t; return std::is_aggregate(); # else return true; diff --git a/include/boost/pfr/traits.hpp b/include/boost/pfr/traits.hpp index 946a219..71bb419 100644 --- a/include/boost/pfr/traits.hpp +++ b/include/boost/pfr/traits.hpp @@ -46,11 +46,12 @@ struct is_reflectable : std::integral_constant< bool, boost template struct is_reflectable : std::integral_constant< bool, boost::pfr::is_reflectable::value > {}; +#if BOOST_PFR_ENABLE_IMPLICITLY_REFLECTION /// Checks the input type for the potential to be reflected. /// Use is_reflectable specializations if you are disagree with is_implicitly_reflectable's default decision. template using is_implicitly_reflectable = std::integral_constant< bool, boost::pfr::detail::possible_reflectable(1L) >; - +#endif /// `is_reflectable_v` is a template variable that valid when it known that type T can or can't be reflected using Boost.PFR. /// @@ -62,10 +63,12 @@ using is_implicitly_reflectable = std::integral_constant< bool, boost::pfr::deta template constexpr bool is_reflectable_v = is_reflectable::value; +#if BOOST_PFR_ENABLE_IMPLICITLY_REFLECTION /// Checks the input type for the potential to be reflected. /// Use is_reflectable specializations if you are disagree with is_implicitly_reflectable_v's default decision. template constexpr bool is_implicitly_reflectable_v = is_implicitly_reflectable::value; +#endif }} // namespace boost::pfr diff --git a/test/print_config.cpp b/test/print_config.cpp index 7bc0e41..b23940b 100644 --- a/test/print_config.cpp +++ b/test/print_config.cpp @@ -13,6 +13,7 @@ int main() { << "BOOST_PFR_USE_LOOPHOLE == " << BOOST_PFR_USE_LOOPHOLE << '\n' << "BOOST_PFR_USE_STD_MAKE_INTEGRAL_SEQUENCE == " << BOOST_PFR_USE_STD_MAKE_INTEGRAL_SEQUENCE << '\n' << "BOOST_PFR_HAS_GUARANTEED_COPY_ELISION == " << BOOST_PFR_HAS_GUARANTEED_COPY_ELISION << '\n' + << "BOOST_PFR_ENABLE_IMPLICITLY_REFLECTION == " << BOOST_PFR_ENABLE_IMPLICITLY_REFLECTION << '\n' << "__cplusplus == " << __cplusplus << '\n' #ifdef __cpp_structured_bindings << "__cpp_structured_bindings == " << __cpp_structured_bindings << '\n' From 2b4e2922ae094ad3e2e110e2532ef99ed5ac727b Mon Sep 17 00:00:00 2001 From: denzor200 Date: Fri, 16 Dec 2022 19:57:12 +0400 Subject: [PATCH 09/11] fix for sfinae-friendliness issue --- include/boost/pfr/traits.hpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/include/boost/pfr/traits.hpp b/include/boost/pfr/traits.hpp index 71bb419..e8515fa 100644 --- a/include/boost/pfr/traits.hpp +++ b/include/boost/pfr/traits.hpp @@ -36,15 +36,16 @@ namespace boost { namespace pfr { template struct is_reflectable { /* do not has 'value' because value is unknown */ }; -// TODO: need tests to show that these specs are sfinae-friendly +// these specs can't be inherited from 'std::integral_constant< bool, boost::pfr::is_reflectable::value >', +// because it will break the sfinae-friendliness template -struct is_reflectable : std::integral_constant< bool, boost::pfr::is_reflectable::value > {}; +struct is_reflectable : boost::pfr::is_reflectable {}; template -struct is_reflectable : std::integral_constant< bool, boost::pfr::is_reflectable::value > {}; +struct is_reflectable : boost::pfr::is_reflectable {}; template -struct is_reflectable : std::integral_constant< bool, boost::pfr::is_reflectable::value > {}; +struct is_reflectable : boost::pfr::is_reflectable {}; #if BOOST_PFR_ENABLE_IMPLICITLY_REFLECTION /// Checks the input type for the potential to be reflected. From f12f35ac1a0ecafb000e00160068e6247a05a906 Mon Sep 17 00:00:00 2001 From: denzor200 Date: Fri, 16 Dec 2022 23:20:37 +0400 Subject: [PATCH 10/11] resolve review discussions --- doc/pfr.qbk | 2 +- include/boost/pfr/detail/config.hpp | 6 +++--- include/boost/pfr/traits.hpp | 21 ++++----------------- test/print_config.cpp | 2 +- 4 files changed, 9 insertions(+), 22 deletions(-) diff --git a/doc/pfr.qbk b/doc/pfr.qbk index 04634fb..a831a18 100644 --- a/doc/pfr.qbk +++ b/doc/pfr.qbk @@ -468,7 +468,7 @@ By default Boost.PFR [*auto-detects your compiler abilities] and automatically d [[*BOOST_PFR_USE_LOOPHOLE*] [Define to `1` if you wish to override Boost.PFR choice and exploit [@http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2118 CWG 2118] for reflection. Define to `0` to override Boost.PFR choice and disable CWG 2118 usage.]] [[*BOOST_PFR_USE_STD_MAKE_INTEGRAL_SEQUENCE*] [Define to `0` if you are hit by the template instantiation depth issues with `std::make_integer_sequence` and wish to use Boost.PFR version of that metafunction. Define to `1` to override Boost.PFR detection logic. ]] [[*BOOST_PFR_HAS_GUARANTEED_COPY_ELISION*] [Define to `0` if your compiler does not implement C++17 guaranteed copy elision properly and fails to reflect aggregates with non-movable fields. Define to `1` to override Boost.PFR detection logic. ]] - [[*BOOST_PFR_ENABLE_IMPLICITLY_REFLECTION*] [Define to `0` if you are hit by lots of non-effective choices made by implicitly reflection. Define to `1` to override Boost.PFR detection logic. ]] + [[*BOOST_PFR_ENABLE_IMPLICIT_REFLECTION*] [Define to `0` if you are hit by lots of non-effective choices made by implicitly reflection. Define to `1` to override Boost.PFR detection logic. ]] ] diff --git a/include/boost/pfr/detail/config.hpp b/include/boost/pfr/detail/config.hpp index 64a8f97..16470bf 100644 --- a/include/boost/pfr/detail/config.hpp +++ b/include/boost/pfr/detail/config.hpp @@ -77,12 +77,12 @@ # endif #endif -#ifndef BOOST_PFR_ENABLE_IMPLICITLY_REFLECTION +#ifndef BOOST_PFR_ENABLE_IMPLICIT_REFLECTION # if defined(__cpp_lib_is_aggregate) -# define BOOST_PFR_ENABLE_IMPLICITLY_REFLECTION 1 +# define BOOST_PFR_ENABLE_IMPLICIT_REFLECTION 1 # else // There is no way to detect potential ability to be reflectable without std::is_aggregare -# define BOOST_PFR_ENABLE_IMPLICITLY_REFLECTION 0 +# define BOOST_PFR_ENABLE_IMPLICIT_REFLECTION 0 # endif #endif diff --git a/include/boost/pfr/traits.hpp b/include/boost/pfr/traits.hpp index e8515fa..79d8f43 100644 --- a/include/boost/pfr/traits.hpp +++ b/include/boost/pfr/traits.hpp @@ -20,7 +20,7 @@ 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 CAN(and in some difficult cases - SHOULD) specialize is_reflectable on his own. +/// Every user may(and in some difficult cases - should) specialize is_reflectable on his own. /// /// \b Example: /// \code @@ -32,7 +32,6 @@ namespace boost { namespace pfr { /// \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 /// -/// \customadaptor using is_reflectable trait and so others. template struct is_reflectable { /* do not has 'value' because value is unknown */ }; @@ -47,26 +46,14 @@ struct is_reflectable : boost::pfr::is_reflectable struct is_reflectable : boost::pfr::is_reflectable {}; -#if BOOST_PFR_ENABLE_IMPLICITLY_REFLECTION +#if BOOST_PFR_ENABLE_IMPLICIT_REFLECTION /// Checks the input type for the potential to be reflected. -/// Use is_reflectable specializations if you are disagree with is_implicitly_reflectable's default decision. +/// Specialize is_reflectable if you are disagree with is_implicitly_reflectable's default decision. template using is_implicitly_reflectable = std::integral_constant< bool, boost::pfr::detail::possible_reflectable(1L) >; -#endif -/// `is_reflectable_v` is a template variable that valid when it known that type T can or can't be reflected using Boost.PFR. -/// -/// \b Example: -/// \code -/// template>* = nullptr> -/// T tag_invoke(boost::json::value_to_tag, const boost::json::value& jv); // overload for definitely reflectable type -/// \endcode -template -constexpr bool is_reflectable_v = is_reflectable::value; - -#if BOOST_PFR_ENABLE_IMPLICITLY_REFLECTION /// Checks the input type for the potential to be reflected. -/// Use is_reflectable specializations if you are 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 constexpr bool is_implicitly_reflectable_v = is_implicitly_reflectable::value; #endif diff --git a/test/print_config.cpp b/test/print_config.cpp index b23940b..a720b3f 100644 --- a/test/print_config.cpp +++ b/test/print_config.cpp @@ -13,7 +13,7 @@ int main() { << "BOOST_PFR_USE_LOOPHOLE == " << BOOST_PFR_USE_LOOPHOLE << '\n' << "BOOST_PFR_USE_STD_MAKE_INTEGRAL_SEQUENCE == " << BOOST_PFR_USE_STD_MAKE_INTEGRAL_SEQUENCE << '\n' << "BOOST_PFR_HAS_GUARANTEED_COPY_ELISION == " << BOOST_PFR_HAS_GUARANTEED_COPY_ELISION << '\n' - << "BOOST_PFR_ENABLE_IMPLICITLY_REFLECTION == " << BOOST_PFR_ENABLE_IMPLICITLY_REFLECTION << '\n' + << "BOOST_PFR_ENABLE_IMPLICIT_REFLECTION == " << BOOST_PFR_ENABLE_IMPLICIT_REFLECTION << '\n' << "__cplusplus == " << __cplusplus << '\n' #ifdef __cpp_structured_bindings << "__cpp_structured_bindings == " << __cpp_structured_bindings << '\n' From 578b5b2ac2c0a49ce7afb02ba562f8484bf31024 Mon Sep 17 00:00:00 2001 From: denzor200 Date: Fri, 16 Dec 2022 23:37:19 +0400 Subject: [PATCH 11/11] tests for new traits --- test/run/is_implicitly_reflectable.cpp | 83 ++++++++++++++++++ test/run/is_reflectable.cpp | 112 +++++++++++++++++++++++++ 2 files changed, 195 insertions(+) create mode 100644 test/run/is_implicitly_reflectable.cpp create mode 100644 test/run/is_reflectable.cpp diff --git a/test/run/is_implicitly_reflectable.cpp b/test/run/is_implicitly_reflectable.cpp new file mode 100644 index 0000000..38ff816 --- /dev/null +++ b/test/run/is_implicitly_reflectable.cpp @@ -0,0 +1,83 @@ +// Copyright (c) 2022 Denis Mikhailov +// +// 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 +#include +#include // for std::true_type, std::false_type and std::is_aggregate + +namespace boost { namespace pfr { + struct boost_fusion_tag; + struct boost_json_tag; +}} + +struct Aggregate {}; +using Nonaggregate = int; + +#if defined(__cpp_lib_is_aggregate) +static_assert(std::is_aggregate::value && !std::is_aggregate::value, ""); +#endif + +using Reflectable = short; +struct Nonrefrectable {}; + +using ReflectableBoostFusion = short; +struct NonrefrectableBoostFusion {}; + +using ReflectableBoostJson = short; +struct NonrefrectableBoostJson {}; + +namespace boost { namespace pfr { + template struct is_reflectable : std::true_type {}; + template struct is_reflectable : std::false_type {}; + template<> struct is_reflectable : std::true_type {}; + template<> struct is_reflectable : std::false_type {}; + template<> struct is_reflectable : std::true_type {}; + template<> struct is_reflectable : std::false_type {}; +}} + + +#if BOOST_PFR_ENABLE_IMPLICIT_REFLECTION +template +void assert_reflectable() { + static_assert(boost::pfr::is_implicitly_reflectable_v, ""); + static_assert(boost::pfr::is_implicitly_reflectable_v, ""); + static_assert(boost::pfr::is_implicitly_reflectable_v, ""); + static_assert(boost::pfr::is_implicitly_reflectable_v, ""); +} + +template +void assert_non_reflectable() { + static_assert(!boost::pfr::is_implicitly_reflectable_v, ""); + static_assert(!boost::pfr::is_implicitly_reflectable_v, ""); + static_assert(!boost::pfr::is_implicitly_reflectable_v, ""); + static_assert(!boost::pfr::is_implicitly_reflectable_v, ""); +} +#endif // #if BOOST_PFR_ENABLE_IMPLICIT_REFLECTION + +int main() { +#if BOOST_PFR_ENABLE_IMPLICIT_REFLECTION + std::cout << "Implicit reflection is available in this platform.." << std::endl; + { + using tag = boost::pfr::boost_json_tag; + assert_reflectable(); + assert_non_reflectable(); + assert_reflectable(); + assert_non_reflectable(); + assert_reflectable(); + assert_non_reflectable(); + } + + { + using tag = boost::pfr::boost_fusion_tag; + assert_reflectable(); + assert_non_reflectable(); + assert_reflectable(); + assert_non_reflectable(); + assert_reflectable(); + assert_non_reflectable(); + } +#endif // #if BOOST_PFR_ENABLE_IMPLICIT_REFLECTION +} + diff --git a/test/run/is_reflectable.cpp b/test/run/is_reflectable.cpp new file mode 100644 index 0000000..fe737fb --- /dev/null +++ b/test/run/is_reflectable.cpp @@ -0,0 +1,112 @@ +// Copyright (c) 2022 Denis Mikhailov +// +// 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 +#include // for std::true_type, std::false_type + +namespace boost { namespace pfr { + struct boost_fusion_tag; + struct boost_json_tag; +}} + +struct Reflectable {}; +struct Nonrefrectable {}; +struct Unknown {}; + +struct ReflectableBoostFusion {}; +struct NonrefrectableBoostFusion {}; + +struct ReflectableBoostJson {}; +struct NonrefrectableBoostJson {}; + +namespace boost { namespace pfr { + template struct is_reflectable : std::true_type {}; + template struct is_reflectable : std::false_type {}; + template<> struct is_reflectable : std::true_type {}; + template<> struct is_reflectable : std::false_type {}; + template<> struct is_reflectable : std::true_type {}; + template<> struct is_reflectable : std::false_type {}; +}} + + + + +namespace helpers { +template +constexpr decltype(boost::pfr::is_reflectable::value) is_reflectability_known(long) { + return true; +} + +template +constexpr bool is_reflectability_known(int) { + return false; +} +} + +template +void assert_reflectable_impl() { + static_assert(helpers::is_reflectability_known(1L), ""); + static_assert(boost::pfr::is_reflectable::value, ""); +} + +template +void assert_non_reflectable_impl() { + static_assert(helpers::is_reflectability_known(1L), ""); + static_assert(!boost::pfr::is_reflectable::value, ""); +} + +template +void assert_unknown_impl() { + static_assert(!helpers::is_reflectability_known(1L), ""); +} + +template +void assert_reflectable() { + assert_reflectable_impl(); + assert_reflectable_impl(); + assert_reflectable_impl(); + assert_reflectable_impl(); +} + +template +void assert_non_reflectable() { + assert_non_reflectable_impl(); + assert_non_reflectable_impl(); + assert_non_reflectable_impl(); + assert_non_reflectable_impl(); +} + +template +void assert_unknown() { + assert_unknown_impl(); + assert_unknown_impl(); + assert_unknown_impl(); + assert_unknown_impl(); +} + +int main() { + { + using tag = boost::pfr::boost_json_tag; + assert_reflectable(); + assert_non_reflectable(); + assert_unknown(); + assert_unknown(); + assert_unknown(); + assert_reflectable(); + assert_non_reflectable(); + } + + { + using tag = boost::pfr::boost_fusion_tag; + assert_reflectable(); + assert_non_reflectable(); + assert_unknown(); + assert_reflectable(); + assert_non_reflectable(); + assert_unknown(); + assert_unknown(); + } +} +