2
0
mirror of https://github.com/boostorg/pfr.git synced 2026-01-19 04:22:13 +00:00

Write docs

This commit is contained in:
denzor200
2023-09-02 22:42:54 +03:00
parent 9b2817a52b
commit fcfca74355
7 changed files with 184 additions and 15 deletions

View File

@@ -32,6 +32,7 @@ local doxygen_params =
<doxygen:param>"ALIASES= \\
\"forcedlink{1}=\\xmlonly<link linkend='boost.pfr.\\1'>\\endxmlonly boost::pfr::\\1\\xmlonly</link>\\endxmlonly\" \\
\"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\" \\
\"fnrefl=\\b See \\b Also : \\xmlonly<link linkend='boost_pfr.tutorial.reflection_of_field_names'>\\endxmlonly 'Reflection of field names' \\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\" \\
"

View File

@@ -183,14 +183,14 @@ Boost.PFR adds the following out-of-the-box functionality for aggregate initiali
* access to members by index or type
* access to member's names by index
* member type retrieval
* methods for cooperation with `std::tuple`
* methods for cooperation with `std::tuple` for members
* methods for cooperation with `std::array` for member's names
* 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].
[caution Recommended C++ Standards are C++17 and above. Library requires at least C++14! Pre C++14 compilers (C++11, C++03...) are not supported]
[caution Recommended C++ Standards are C++20 and above. C++17 completely enough for a user who doesn't want accessing name of structure member. Library requires at least C++14! Pre C++14 compilers (C++11, C++03...) are not supported]
[endsect]
@@ -205,6 +205,9 @@ Boost.PFR is a header only library that does not depend on Boost. You can just c
[
[ [pfr_quick_examples_get] ]
[ [funcref boost::pfr::get] ]
][
[ [pfr_quick_examples_get_name] ]
[ [funcref boost::pfr::get_name] ]
][
[ [pfr_quick_examples_ops] ]
[
@@ -450,12 +453,21 @@ error: static_assert failed "====================> Boost.PFR: For safety reasons
[endsect]
[section Reflection of field names ]
[pfr_example_get_name]
See [link boost_pfr.limitations_of_field_names_reflection [*Limitations of field names reflection]] and [link boost_pfr.limitations_and_configuration [*Limitations and Configuration]].
[endsect]
[endsect]
[section Limitations and Configuration]
[caution Recommended C++ Standards are C++17 and above. Library requires at least C++14! Pre C++14 compilers (C++11, C++03...) are not supported. ]
[caution Recommended C++ Standards are C++20 and above. C++17 completely enough for a user who doesn't want accessing name of structure member. Library requires at least C++14! Pre C++14 compilers (C++11, C++03...) are not supported. ]
Boost.PFR library works with types that satisfy the requirements of `SimpleAggregate`: aggregate types without base classes, `const` fields, references, or C arrays:
@@ -477,7 +489,7 @@ struct aggregate : empty { // not a SimpleAggregate
```
The library may work with aggregates that don't satisfy the requirements of `SimpleAggregate`, but the behavior tends to be non-portable.
Boost.PFR's extraction of field name works with a `SimpleAggregate` which variables are able to be declared in any other translation unit.
Boost.PFRs extraction of field name works with a `SimpleAggregate` which variables are able to be declared in any other translation unit.
It's better not to use this feature with anonymous structure, local structure or a structure defined inside anonymous namespace.
```
@@ -497,6 +509,8 @@ struct {
Field's name extraction may work with a `SimpleAggregate` that does't satisfy such requirements, but the behavior tends to be non-portable.
Try using `-fpermissive` if you have any issue with it.
As you see above extraction of field name feature has requirements of input type, additionally it has some requirements of compiler, see [link boost_pfr.limitations_of_field_names_reflection [*Limitations of field names reflection]] for details.
[h2 Configuration Macro]
By default Boost.PFR [*auto-detects your compiler abilities] and automatically defines the configuration macro into appropriate values. If you wish to override that behavior, just define:
@@ -508,8 +522,8 @@ By default Boost.PFR [*auto-detects your compiler abilities] and automatically d
[[*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_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. ]]
[[*BOOST_PFR_ENABLE_GET_NAME_STATIC*] [On platforms where field's names extracting is not supported, the 'boost/pfr/config.hpp' header defines the BOOST_PFR_ENABLE_GET_NAME_STATIC macro equal to 0. Defining this macro as 0 before including the header disables the ability to get a field's name. ]]
[[*BOOST_PFR_FUNCTION_SIGNATURE*] [TODO: desc it ]]
[[*BOOST_PFR_CORE_NAME_PARSING*] [TODO: desc it ]]
[[*BOOST_PFR_FUNCTION_SIGNATURE*] [On platforms which are unknown by Boost.PFR library, the 'boost/pfr/config.hpp' header defines the BOOST_PFR_FUNCTION_SIGNATURE macro equal to "". Defining this macro before including the header might help the library to work on your specific platform. See details [link boost_pfr.limitations_of_field_names_reflection [*here]]. ]]
[[*BOOST_PFR_CORE_NAME_PARSING*] [On platforms which are unknown by Boost.PFR library, the 'boost/pfr/config.hpp' header defines the BOOST_PFR_CORE_NAME_PARSING macro equal to (0,0,false). Defining this macro before including the header might help the library to work on your specific platform. See details [link boost_pfr.limitations_of_field_names_reflection [*here]]. ]]
[[*BOOST_PFR_ENABLED*] [On platforms where Boost.PFR is not supported, the `boost/pfr/config.hpp` header defines the BOOST_PFR_ENABLED macro equal to 0. Defining this macro as 0 before including the header disables the Boost.PFR library. ]]
]
@@ -527,13 +541,85 @@ The Boost.PFRs reflection has some limitations that depend on a C++ Standard and
* T must be constexpr aggregate initializable and all its fields must be constexpr default constructible
* [funcref boost::pfr::get], [funcref boost::pfr::structure_to_tuple], [funcref boost::pfr::structure_tie], [headerref boost/pfr/core.hpp boost::pfr::tuple_element] require T to be a POD type with built-in types only.
The Boost.PFRs extraction of field name has some limitations that depend on a C++ Standard and compiler capabilities:
* T must be able to be extern.
[endsect]
[section Limitations of field's names reflection]
[section Limitations of field names reflection]
TODO: write the article and make a link on it inside "Limitations and Configuration"
Boost.PFRs extraction of field name has been tested and successfully work on many compilers.
[section Define the BOOST_PFR_FUNCTION_SIGNATURE macro]
If you get the following error during compilation
``
PFRs extraction of field name could not detect your compiler.
Please make the BOOST_PFR_FUNCTION_SIGNATURE macro use
correct compiler macro for getting the whole function name.
Define BOOST_PFR_CORE_NAME_PARSING to correct value after that.
``
then you are using a compiler that was not tested with this library.
[macroref BOOST_PFR_FUNCTION_SIGNATURE] must be defined to a compiler specific macro, that outputs the *whole*
function signature including non-type template parameters.
[endsect]
[section Fixing get_name() output]
Let's assume the structure `namespace A { struct A { int fn; }; }`
If the output of `boost::pfr::get_name<0, A::A>()`
returns not just `fn` but also a lot of text around the `fn`
or does not return name at all
then you are using a compiler that was not tested with this library and you need to setup the
[macroref BOOST_PFR_CORE_NAME_PARSING] macro.
Here is a short instruction:
# get the output of `boost::pfr::get_name<0, A::A>()`
# define [macroref BOOST_PFR_CORE_NAME_PARSING] to
`(skip_at_begin, skip_at_end, false, "")`, where
* `skip_at_begin` is equal to characters count before the first occurrence of `fn` in output
* `skip_at_end` is equal to characters count after last occurrence of `fn` in output
# check that `boost::pfr::get_name<0, A::A>()` returns "fn"
# if it does not return `fn`, then define BOOST_PFR_CORE_NAME_PARSING to
`(skip_at_begin, skip_at_end, true, "T = ")`, where
* `skip_at_begin` is equal to `skip_at_begin` at step 2
* `skip_at_end` is equal to `skip_at_end` at step 2
* `"T = "` is equal to characters that are right before the `fn` in output
# (optional, but highly recommended) [@https://github.com/boostorg/pfr/issues create ticket] with
feature request to add your compiler to supported compilers list. Include
parameters provided to `BOOST_PFR_CORE_NAME_PARSING` macro.
Consider the following example:
`boost::pfr::get_name<0, A::A>()` returns
"auto __cdecl boost::pfr::detail::name_of_field_impl<struct A::A,&a->fn>(void) noexcept" while compiled with `-DBOOST_PFR_CORE_NAME_PARSING (0,0,false,"")`. Then you shall set
`skip_at_begin` to `sizeof("auto __cdecl boost::pfr::detail::name_of_field_impl<") - 1`
and `skip_at_end` to `sizeof(">(void) noexcept") - 1` and last parameter of macro to `"->"`.
``
#define BOOST_PFR_CORE_NAME_PARSING (52, 16, true, "->")
``
Another example:
`boost::pfr::get_name<0, A::A>()` returns
"consteval auto boost::pfr::detail::name_of_field_impl() [with MsvcWorkaround = A::A; auto ptr = (& a.A::A::fn)]" while compiled with `-DBOOST_PFR_CORE_NAME_PARSING (0,0,false,"")`. Then you shall set
`skip_at_begin` to `0`
and `skip_at_end` to `sizeof(")]") - 1` and last parameter of macro to `backward("::")`.
``
#define BOOST_PFR_CORE_NAME_PARSING (0, 2, true, backward("::"))
``
[endsect]
[endsect]

43
example/get_name.cpp Normal file
View File

@@ -0,0 +1,43 @@
// Copyright (c) 2023 Bela Schaum, X-Ryl669, 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)
// Initial implementation by Bela Schaum, https://github.com/schaumb
// The way to make it union and UB free by X-Ryl669, https://github.com/X-Ryl669
//
#include <boost/pfr/config.hpp>
#if BOOST_PFR_ENABLE_GET_NAME_STATIC
//[pfr_example_get_name
/*`
Since C++20 it's possible to read name of structure fields by index using Boost.PFR library.
The following example shows how to do it using [funcref boost::pfr::get_name].
Let's define some structure:
*/
#include <boost/pfr/core_name.hpp>
struct foo { // defining structure
int some_integer;
char c;
};
/*`
We can access field's names of that structure by index:
*/
constexpr auto r1 = boost::pfr::get_name<0, foo>(); // reading name of field with index 0, returns string `some_integer`
constexpr auto r2 = boost::pfr::get_name<1, foo>(); // reading name of field with index 1, returns string `c`
//] [/pfr_example_get_name]
#endif
int main() {
#if BOOST_PFR_ENABLE_GET_NAME_STATIC
if (r1 != "some_integer") return 1;
if (r2 != "c") return 2;
#endif
return 0;
}

View File

@@ -106,6 +106,22 @@ void test_examples() {
//]
}
#if BOOST_PFR_ENABLE_GET_NAME_STATIC
{
//[pfr_quick_examples_get_name
// Get name of field by index
struct sample {
int f1;
long f2;
};
std::cout << boost::pfr::get_name<0, sample>()
<< boost::pfr::get_name<1, sample>(); // Outputs: f1 f2
//]
}
#endif
#if BOOST_PFR_USE_CPP17 || BOOST_PFR_USE_LOOPHOLE
{
//[pfr_quick_examples_structure_to_tuple

View File

@@ -115,25 +115,22 @@
|| defined(__clang__)
# define BOOST_PFR_FUNCTION_SIGNATURE __PRETTY_FUNCTION__
# else
// TODO: specify in the doc that this is unsupported value
# define BOOST_PFR_FUNCTION_SIGNATURE ""
# endif
#endif
#ifndef BOOST_PFR_CORE_NAME_PARSING
# if defined(_MSC_VER)
// sizeof("auto __cdecl boost::pfr::detail::name_of_field_impl<") - 1, sizeof(">(void) noexcept") - 1
// sizeof("auto __cdecl boost::pfr::detail::name_of_field_impl<") - 1, sizeof(">(void) noexcept") - 1
# define BOOST_PFR_CORE_NAME_PARSING (52, 16, "->")
# elif defined(__clang__)
// sizeof("auto boost::pfr::detail::name_of_field_impl() [MsvcWorkaround = ") - 1, sizeof("}]") - 1
// sizeof("auto boost::pfr::detail::name_of_field_impl() [MsvcWorkaround = ") - 1, sizeof("}]") - 1
# define BOOST_PFR_CORE_NAME_PARSING (64, 2, ".")
# elif defined(__GNUC__)
// sizeof("consteval auto boost::pfr::detail::name_of_field_impl() [with MsvcWorkaround = ") - 1, sizeof(")]") - 1
// sizeof("consteval auto boost::pfr::detail::name_of_field_impl() [with MsvcWorkaround = ") - 1, sizeof(")]") - 1
# define BOOST_PFR_CORE_NAME_PARSING (79, 2, "::")
# else
// TODO: specify in the doc that this is unsupported value
// TODO: .. and even if value is supported, there still no gurantee that it correct! also make a compile-fail test for such case
// Deafult parser for other platforms... Just skip nothing!
// Deafult parser for other platforms... Just skip nothing!
# define BOOST_PFR_CORE_NAME_PARSING (0, 0, "")
# endif
#endif

View File

@@ -24,8 +24,24 @@
#include <boost/pfr/tuple_size.hpp>
/// \file boost/pfr/core_name.hpp
/// Contains functions \forcedlink{get_name} and \forcedlink{names_as_array} to know which names each field of any \aggregate has.
///
/// \fnrefl for details.
///
/// \b Synopsis:
namespace boost { namespace pfr {
/// \brief Returns name of a field with index `I` in \aggregate `T`.
///
/// \b Example:
/// \code
/// struct my_struct { int i, short s; };
///
/// assert(boost::pfr::get_name<0, my_struct>() == "i");
/// assert(boost::pfr::get_name<1, my_struct>() == "s");
/// \endcode
template <std::size_t I, class T>
constexpr auto get_name() noexcept {
return detail::get_name<T, I>();
@@ -37,6 +53,14 @@ constexpr auto get_name() noexcept {
// return detail::sequence_tuple::get_by_type_impl<U>( detail::tie_as_names_tuple<T>() );
// }
/// \brief Creates a `std::array` from names of fields of an \aggregate `T`.
///
/// \b Example:
/// \code
/// struct my_struct { int i, short s; };
/// std::array<std::string_view> t = boost::pfr::structure_to_tuple<my_struct>();
/// assert(get<0>(t) == "i");
/// \endcode
template <class T>
constexpr auto names_as_array() noexcept {
return detail::make_stdarray_from_tietuple(

View File

@@ -116,6 +116,8 @@ constexpr auto clang_workaround(const T& arg) noexcept {
template<typename T>
constexpr const T& clang_workaround(const T& arg) noexcept {
// It's everything OK with this compiler
// so we don't need a workaround here
return arg;
}