pfr
pfr copied to clipboard
Make pfr more friendly for integrating into other libraries?
Description of issue Now i'm working with Boost.Fusion extension for Boost.PFR, i decomposed it into 3 PR's and opened these PR's here: https://github.com/boostorg/fusion/pull/241, here https://github.com/boostorg/fusion/pull/242 and here https://github.com/boostorg/fusion/pull/243. Review is moving on, there is some wishes from reviewers(more on that later). First, I would like to talk about such a problem like 3 PR's is too much code and the review takes too long. I suggest to make pfr more adaptable and more friendly to adapt into other libraries(not only fusion).
Suggested solution
- To implement two functions:
boost::pfr::viewboost::pfr::view_fields
- To implement
BOOST_PFR_REGISTRATE_REFLECTABLEmacro. - To add
boost::pfr::is_reflectabletrait. Example of using trait:
struct A {};
struct B {};
struct C {};
BOOST_PFR_REGISTRATE_REFLECTABLE(A)
using boost::pfr::is_reflectable;
is_reflectable<A>::value; //< true
is_reflectable<decltype(boost::pfr::view_fields(B{}))>::value; //< true
is_reflectable<C>::value; //< false
- To use
boost::pfr::is_reflectabletrait for create overloading of compare/io operators and specialization ofstd::hashfunction. Examples of using these overloads:
#include <boost/pfr/ops.hpp>
template <class T>
struct uniform_comparator_less {
bool operator()(const T& lhs, const T& rhs) const noexcept {
// If T has operator< or conversion operator then it is used.
return boost::pfr::view(lhs) < boost::pfr::view(rhs);
}
};
#include <boost/pfr/functions_for.hpp>
struct pair_like {
int first;
short second;
};
BOOST_PFR_REGISTRATE_REFLECTABLE(pair_like) // Added pair_like's specialization for is_reflectable trait.
// ...
assert(pair_like{1, 2} < pair_like{1, 3});
#include <boost/pfr/io_fields.hpp>
struct pair_like {
int first;
std::string second;
};
inline std::ostream& operator<<(std::ostream& os, const pair_like& x) {
return os << bost::pfr::view_fields(x);
}
- To declare
io,eq,ne,lt,gt,le,ge,hash_value,io_fields,eq_fields,ne_fields,lt_fields,gt_fields,le_fields,ge_fields,hash_fields,BOOST_PFR_FUNCTIONS_FORas deprecated, and to actualize https://www.boost.org/doc/libs/1_75_0/doc/html/boost_pfr/tutorial.html#boost_pfr.tutorial.three_ways_of_getting_operators.
Conclusion
If everything planned can be done, then the PFR will be adapted as easily as the std::tuple, it will be just one small PR.
What further prospects will we get if we implement this approach:
- To extend
is_reflectabletrait, to implement it's code for auto detect that user defined type is reflectable. It discussed here: https://github.com/boostorg/pfr/issues/56 and reviewers from Fusion wish it. - To give for PFR users a fallback, in case the automation fails:
-
BOOST_PFR_FORCE_REFLECTABLEmacro (just alias forBOOST_PFR_REGISTRATE_REFLECTABLE) -BOOST_PFR_FORCE_NON_REFLECTABLEmacro -boost::pfr::force_reflectablefunction (just alias forboost::pfr::view_fields) -boost::pfr::force_non_reflectablefunction
struct A {};
struct B {};
struct C {};
BOOST_PFR_FORCE_REFLECTABLE(A)
BOOST_PFR_FORCE_NON_REFLECTABLE(B)
using boost::pfr::is_reflectable;
using boost::pfr::force_reflectable;
using boost::pfr::force_non_reflectable;
is_reflectable<A>::value; //< true
is_reflectable<B>::value; //< false
is_reflectable<decltype(force_reflectable(C{}))>::value; //< true
is_reflectable<decltype(force_non_reflectable(C{}))>::value; //< false
- To move it all into separate
experimentalinclude section.
I'd appreciate help with all the above points
I wrote a draft code for this functionality. The whole PR with docs and tests will be in a nearest future. I suppose that these changes will be super clean and won't get stuck on review.
Draft: https://godbolt.org/z/Y98xhajb8
Not all of the planned was done, some points turned out to be impracticable (and inexpedient), I will describe in more detail about deviations from the plan in the PR.
How can we use modified PFR to make other libraries extensions? Like these: Boost Json extension sample: https://godbolt.org/z/GYY8e9jMs Boost Fusion extension sample: https://godbolt.org/z/Y6713Ej4a Boost Spirit with Fusions extension sample: https://godbolt.org/z/9cYvea3b7
Also, i want to say that the most difficult part of the future PR is the implementation of pfr::view. It is an wrap-object, that can be a reference to underlying value or can be an owner, can be forwarded and can be implicitly casted to its underlying type.
I didn't find a solution in all C++ libraries that i know, so i just reinvented the wheel.
View: https://godbolt.org/z/rYhdnv9MW
I suppose that this wrap-object can slow down the review for us.
We decided to select yet more simple strategy for integrating. In the Fusion side PFR will be fallback, and will be selected when no other reflection not found for T.
It can be solved using pfr::is_implicitly_reflectable trait, no need for difficult pfr::view_t.
Draft: https://godbolt.org/z/P1481orTM
The whole PR in progress, also sample for Fusion and Spirit. It all will be available in the nearest future.
We decided to select yet more simple strategy for integrating. In the Fusion side PFR will be fallback, and will be selected when no other reflection not found for T.
It can be solved using
pfr::is_implicitly_reflectabletrait, no need for difficultpfr::view_t.Draft: https://godbolt.org/z/P1481orTM
The whole PR in progress, also sample for Fusion and Spirit. It all will be available in the nearest future.
We also need to apply patch on the Fusion side, described here: https://github.com/boostorg/fusion/issues/231
We decided to select yet more simple strategy for integrating. In the Fusion side PFR will be fallback, and will be selected when no other reflection not found for T.
It can be solved using
pfr::is_implicitly_reflectabletrait, no need for difficultpfr::view_t.Draft: https://godbolt.org/z/P1481orTM
The whole PR in progress, also sample for Fusion and Spirit. It all will be available in the nearest future.
Look at this: https://github.com/boostorg/pfr/pull/111