[library Boost.PFR
    [quickbook 1.6]
    [version 2.2]
    [copyright 2016-2025 Antony Polukhin]
    [category Language Features Emulation]
    [license
        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])
    ]
]

[section Intro]

Boost.PFR is a C++14 library for a very basic reflection. It gives you access to structure elements by index and provides other `std::tuple` like methods for user defined types without macro or boilerplate code:

[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]].


[h2 Usecase example]

Imagine that you are writing the wrapper library for a database. Depending on the usage of Boost.PFR users code will look differently:

[table:hand_made_vs_pfr_1
[[ Without Boost.PFR ] [ With Boost.PFR ]]
[[
```
#include <db/api.hpp>

struct user_info {
    std::int64_t id;
    std::string name, email, login;
};

user_info retrieve_friend(std::string_view name) {
    std::tuple info_tuple
      = db::one_row_as<std::int64_t, std::string, std::string, std::string>(
        "SELECT id, name, email, login FROM user_infos WHERE name=$0",
        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.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
    );

    return friend_info;
}
```
][
```
#include <db/api.hpp>

struct user_info {
    std::int64_t id;
    std::string name, email, login;
};

user_info retrieve_friend(std::string_view name) {
    // With Boost.PFR you can put data directly into user provided structures
    user_info info = db::one_row_as<user_info>(
        "SELECT id, name, email, login FROM user_infos WHERE name=$0",
        name
    );

    ////////////////// 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     /////////////////////////////////////////////////////////
                        // Boost.PFR allows you to iterate over all the fields
                        // of a user provided structure
                        //
    );

    return friend_info;
}
```
]]
]

Otherwise your library could require a customization point for a user type:


[table:hand_made_vs_pfr_2
[[ Without Boost.PFR ] [ With Boost.PFR ]]
[[
```
#include <db/api.hpp>

struct user_info {
    std::int64_t id;
    std::string name, email, login;
};

/// Customizations via hand-written code ////////////////////////////////////////
auto db_api_tie(user_info& ui) noexcept {
    return std::tie(ui.id, ui.name, ui.email, ui.login);
}

auto db_api_tie(const user_info& ui) noexcept {
    return std::tie(ui.id, ui.name, ui.email, ui.login);
}
/////////////////////////////////////////////////////////////////////////////////
```
][
```
#include <db/api.hpp>

struct user_info {
    std::int64_t id;
    std::string name, email, login;
};

//////// With Boost.PFR there's no need in hand written customizations //////////







/////////////////////////////////////////////////////////////////////////////////
```
]]
]


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<boost::pfr::is_implicitly_reflectable_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 ]

Boost.PFR adds the following out-of-the-box functionality for aggregate initializable structures:

* comparison functions
* heterogeneous comparators
* hash
* IO streaming
* access to members by index or type
* access to member's names by index
* member type retrieval
* 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++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]


[section Short Examples for the Impatient]

[import ../example/quick_examples.cpp]


[table:quick_examples
[[ Code snippet ] [ Reference: ]]
[
    [ [pfr_quick_examples_get] ]
    [ [funcref boost::pfr::get] ]
][
    [ [pfr_quick_examples_get_name] ]
    [ [funcref boost::pfr::get_name] ]
][
    [ [pfr_quick_examples_ops] ]
    [

        [headerref boost/pfr/ops.hpp Header boost/pfr/ops.hpp]:

        * [funcref boost::pfr::eq]

        * [funcref boost::pfr::ne]

        * [funcref boost::pfr::gt]

        * ...

    ]
][
    [ [pfr_quick_examples_for_each] ]
    [
        [funcref boost::pfr::for_each_field]

        [funcref boost::pfr::io]
    ]
][
    [ [pfr_quick_examples_for_each_with_name] ]
    [ [funcref boost::pfr::for_each_field_with_name] ]
][
    [ [pfr_quick_examples_functions_for] ]
    [ [macroref BOOST_PFR_FUNCTIONS_FOR] ]
][
    [ [pfr_quick_examples_eq_fields] ]
    [
        [headerref boost/pfr/ops_fields.hpp Header boost/pfr/ops_fields.hpp ]:

        * [funcref boost::pfr::eq_fields]

        * [funcref boost::pfr::ne_fields]

        * [funcref boost::pfr::gt_fields]

        * ...

        [headerref boost/pfr/io_fields.hpp Header boost/pfr/io_fields.hpp ]

        * [funcref boost::pfr::io_fields]

    ]
][
    [ [pfr_quick_examples_for_each_idx] ]
    [ [funcref boost::pfr::for_each_field] ]
][
    [ [pfr_quick_examples_tuple_size] ]
    [ [classref boost::pfr::tuple_size] ]
][
    [ [pfr_quick_examples_structure_to_tuple] ]
    [ [funcref boost::pfr::structure_to_tuple] ]
][
    [ [pfr_quick_examples_structure_tie] ]
    [ [funcref boost::pfr::structure_tie] ]
]]



[endsect]


[section Tutorial]

[import ../example/sample_printing.cpp]
[import ../example/get.cpp]
[import ../example/get_name.cpp]


[section Why tuples are bad and aggregates are more preferable?]

`std::tuple` and `std::pair` are good for generic programming, however they have disadvantages. First of all, code that uses them becomes barely readable. Consider two definitions:

[table:tuples_vs_aggregates
[[ Tuple ] [ Aggregate ]]
[[
```
using auth_info_tuple = std::tuple<
    std::int64_t, // What does this integer represents?
    std::int64_t,
    std::time_t
>;
```
][
```
struct auth_info_aggregate {
    std::int64_t user_id;    // Oh, now I see!
    std::int64_t session_id;
    std::time_t  valid_till;
};
```
]]
]

Definition via aggregate initializable structure is much more clear. Same story with usages: `return std::get<1>(value);` vs. `return value.session_id;`.

Another advantage of aggregates is a more efficient copy, move construction and assignments.

Because of the above issues some guidelines recommend to [*use aggregates instead of tuples]. However aggregates fail when it comes to the functional like programming.

Boost.PFR library [*provides tuple like methods for aggregate initializable structures], making aggregates usable in contexts where only tuples were useful.

[endsect]

[section Accessing structure member by index] [pfr_example_get] [endsect]
[section Custom printing of aggregates] [pfr_sample_printing] [endsect]


[section Three ways of getting operators ]

There are three ways to start using Boost.PFR hashing, comparison and streaming for type `T` in your code. Each method has its own drawbacks and suits own cases.

[table:ops_comp Different approaches for operators
    [[ Approach
    ][ When to use
    ][ Operators could be found by ADL ][ Works for local types ][ Usable locally, without affecting code from other scopes ][ Ignores implicit conversion operators ][ Respects user defined operators ]]

    [[
        [headerref boost/pfr/ops.hpp boost/pfr/ops.hpp: eq, ne, gt, lt, le, ge]

        [headerref boost/pfr/io.hpp boost/pfr/io.hpp: io]
    ][
        Use when you need to compare values by provided for them operators or via field-by-field comparison.
    ][ no ][ yes ][ yes ][ no ][ yes ]]

    [[
        [macroref BOOST_PFR_FUNCTIONS_FOR BOOST_PFR_FUNCTIONS_FOR(T)]
    ][
        Use near the type definition to define the whole set of operators for your type.
    ][ yes ][ no ][ no ][ yes for T ] [ no (compile time error) ]]

    [[
        [headerref boost/pfr/ops_fields.hpp boost/pfr/ops_fields.hpp: eq_fields, ne_fields, gt_fields, lt_fields, le_fields, ge_fields]

        [headerref boost/pfr/io.hpp boost/pfr/io_fields.hpp: io_fields]
    ][
        Use to implement the required set of operators for your type.
    ][ no ][ yes ][ yes ][ yes ][ yes ]]
]

More detailed description follows:

[*1. `eq, ne, gt, lt, le, ge, io` approach]

This method is good if you're writing generic algorithms and need to use operators from Boost.PFR only if there are no operators defined for the type:

```
#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::lt(lhs, rhs);
    }
};
```
This methods effects are local to the function. It works even for local types, like structures defined in functions.


[*2. BOOST_PFR_FUNCTIONS_FOR(T) approach]

This method is good if you're writing a structure and wish to define operators for that structure.
```
#include <boost/pfr/functions_for.hpp>

struct pair_like {
    int first;
    short second;
};

BOOST_PFR_FUNCTIONS_FOR(pair_like)   // Defines operators

// ...

assert(pair_like{1, 2} < pair_like{1, 3});
```
Argument Dependant Lookup works well. `std::less` will find the operators for `struct pair_like`. [macroref BOOST_PFR_FUNCTIONS_FOR BOOST_PFR_FUNCTIONS_FOR(T)]
can not be used for local types. It does not respect conversion operators of `T`, so for example the following code
will output different values:
```
#include <boost/pfr/functions_for.hpp>

struct empty {
    operator std::string() { return "empty{}"; }
};
// Uncomment to get different output:
// BOOST_PFR_FUNCTIONS_FOR(empty)

// ...
std::cout << empty{}; // Outputs `empty{}` if BOOST_PFR_FUNCTIONS_FOR(empty) is commented out, '{}' otherwise.
```

[*3. `eq_fields, ne_fields, gt_fields, lt_fields, le_fields, ge_fields, io_fields` approach]

This method is good if you're willing to provide only some operators for your type:

```
#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::io_fields(x);
}
```

All the `*_fields` functions do ignore user defined operators and work only with fields of a type. This makes them perfect for defining you own operators.

[endsect]


[section Reflection of unions ]

You could use tuple-like representation if a type contains union. But be sure that operations for union are manually defined:

```
#include <boost/pfr/ops.hpp>

union test_union {
    int i;
    float f;
};

inline bool operator==(test_union l, test_union r) noexcept; // Compile time error without this operator

bool some_function(test_union f1, test_union f2) {
    return boost::pfr::eq(f1, f2); // OK
}

```

Reflection of unions is disabled in the Boost.PFR library for safety reasons. Alas, there's no way to find out [*active] member of a union and accessing an inactive member is an Undefined Behavior. For example, library could always return the first member, but ostreaming `u` in `union {char* c; long long ll; } u; u.ll= 1;` will crash your program with an invalid pointer dereference.

Any attempt to reflect unions leads to a compile time error. In many cases a static assert is triggered that outputs the following message:

```
error: static_assert failed "====================> Boost.PFR: For safety reasons it is forbidden
        to reflect unions. See `Reflection of unions` section in the docs for more info."
```

[endsect]


[section Reflection of field name ]

[pfr_example_get_name]

See [link boost_pfr.limitations_and_configuration [*Limitations and Configuration]].

[endsect]

[endsect]


[section Limitations and Configuration]

[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:

```
struct simple_aggregate {  // SimpleAggregate
    std::string name;
    int age;
    boost::uuids::uuid uuid;
};

struct empty {             // SimpleAggregate
};

struct aggregate : empty { // not a SimpleAggregate
    std::string name;
    int age;
    boost::uuids::uuid uuid;
};
```
The library may work with aggregates that don't satisfy the requirements of `SimpleAggregate`, but the behavior tends to be non-portable.

Boost.PFRs extraction of field name works with only `SimpleAggregate` types.


[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:
[table:linkmacro Macros
    [[Macro name] [Effect]]
    [[*BOOST_PFR_USE_CPP17*] [Define to `1` if you wish to override Boost.PFR choice and use C++17 structured bindings for reflection. Define to `0` to override Boost.PFR choice and disable C++17 structured bindings usage.]]
    [[*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_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_CORE_NAME_ENABLED*] [On platforms where field name extraction is not supported, the 'boost/pfr/config.hpp' header defines the BOOST_PFR_CORE_NAME_ENABLED macro equal to 0. Defining this macro as 0 before including the header disables the ability to get a field name. ]]
    [[*BOOST_PFR_FUNCTION_SIGNATURE*] [For known compilers defined to a compiler specific macro, that outputs the whole function signature including non-type template parameters. ]]
    [[*BOOST_PFR_CORE_NAME_PARSING*] [Describes extraction of field name from BOOST_PFR_FUNCTION_SIGNATURE macro. See details below. ]]
    [[*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. ]]
]


[h2 Details on Limitations]

The Boost.PFRs reflection has some limitations that depend on a C++ Standard and compiler capabilities:

* Static variables are ignored
* T must be aggregate initializable without base classes
* if T contains C arrays then the result of reflection may differ depending on the C++ version and library configuration
* Additional limitations if [*BOOST_PFR_USE_CPP17 == 0]:
    * Non of the member fields should have a template constructor from one parameter.
    * Additional limitations if [*BOOST_PFR_USE_LOOPHOLE == 0]:
        * 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 should be usable like `extern T t;`, i.e. has a non-internal linkage.

[h2 Adjusting BOOST_PFR_CORE_NAME_PARSING]

`BOOST_PFR_CORE_NAME_PARSING` is already set up for most of the popular compilers. You need to adjust it only
if some static_assert in the library complained on `BOOST_PFR_CORE_NAME_PARSING`.

To do that:

# Build `test/core_name/print_name.cpp` with your compiler and run it
# Define BOOST_PFR_CORE_NAME_PARSING to `(skip_at_begin, skip_at_end, "")`, where
    * `skip_at_begin` is equal to characters count before the first occurrence of `user_defined_field` in output
    * `skip_at_end` is equal to characters count after last occurrence of `user_defined_field` in output
# Check that `test/core_name/print_name.cpp` returns "user_defined_field"
# If it does not return `user_defined_field`, then define BOOST_PFR_CORE_NAME_PARSING to `(skip_at_begin, skip_at_end, "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 `user_defined_field` in output, use `backward("T = ")` to search for the occurange in the string from the right
# (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 [*and] the initial output of `test/core_name/print_name.cpp`.

[endsect]

[section PFR as a C++20 module]

[caution C++20 PFR module support is on early stage, targets and flags may change in the future]

If using CMake of version 3.28.0 or higher define CMake option `-DBUILD_MODULE=1`
to make the `Boost::pfr_module` and `Boost::pfr_module_migration` libraries
available. With `Boost::pfr_module` C++20 module Boost.PFR could be used:

[import ../module/usage_sample.cpp]
[pfr_module_example]

The `Boost::pfr_module_migration` CMake target gives an ability to
mix includes and imports of the PFR library in different translation units.

If not using CMake, then the module could be build manually from the
`module/pfr.cppm` file. If mixing of includes in imports is desired, additionally
define `BOOST_PFR_ATTACH_TO_GLOBAL_MODULE` preprocessor macro to attach all the
module entities to a global module and avoid ODR issues.

For manual module build the following commands could be used for clang compiler:

```
cd pfr/module
clang++ -I ../include -std=c++20 --precompile -x c++-module pfr.cppm
```

After that, the module could be used in the following way:

```
clang++ -std=c++20 -fmodule-file=pfr.pcm pfr.pcm usage_sample.cpp
```

[endsect]

[section How it works]

[h2 Fields count detection and getting references to members]

Short description:

# at compile-time: use aggregate initialization to detect fields count in user-provided structure
    * [*BOOST_PFR_USE_CPP17 == 1]:
        # at compile-time: structured bindings are used to decompose a type `T` to known amount of fields
    * [*BOOST_PFR_USE_CPP17 == 0 && BOOST_PFR_USE_LOOPHOLE == 1]:
        # at compile-time: use aggregate initialization to detect fields count in user-provided structure
        # at compile-time: make a structure that is convertible to anything and remember types it has been converted to during aggregate initialization of user-provided structure
        # at compile-time: using knowledge from previous steps create a tuple with exactly the same layout as in user-provided structure
        # at compile-time: find offsets for each field in user-provided structure using the tuple from previous step
        # at run-time: get pointer to each field, knowing the structure address and each field offset
        # at run-time: a tuple of references to fields is returned => all the tuple methods are available for the structure
    * [*BOOST_PFR_USE_CPP17 == 0 && BOOST_PFR_USE_LOOPHOLE == 0]:
        # at compile-time: let `I` be is an index of current field, it equals 0
        # at run-time: `T` is constructed and field `I` is aggregate initialized using a separate instance of structure that is convertible to anything [note Additional care is taken to make sure that all the information about `T` is available to the compiler and that operations on `T` have no side effects, so the compiler can optimize away the unnecessary temporary objects.]
        # at compile-time: `I += 1`
        # at compile-time: if `I` does not equal fields count goto step [~c.] from inside of the conversion operator of the structure that is convertible to anything
        # at compile-time: using knowledge from previous steps create a tuple with exactly the same layout as in user-provided structure
        # at compile-time: find offsets for each field in user-provided structure using the tuple from previous step
        # at run-time: get pointer to each field, knowing the structure address and each field offset
# at run-time: a tuple of references to fields is returned => all the tuple methods are available for the structure

Long description of some basics: [@https://youtu.be/UlNUNxLtBI0 Antony Polukhin: Better C++14 reflections].
Long description of some basics of C++14 with [link boost_pfr.limitations_and_configuration [*BOOST_PFR_USE_LOOPHOLE == 0]]: [@https://youtu.be/abdeAew3gmQ Antony Polukhin: C++14 Reflections Without Macros, Markup nor External Tooling].
Description of the [*BOOST_PFR_USE_LOOPHOLE == 1] technique by its inventor Alexandr Poltavsky [@http://alexpolt.github.io/type-loophole.html in his blog].

[h2 Field name retrieval]

# at compile-time:
    * Get references to members of an object of type `T` in `constexpr` function
    * Feed the reference from previous as a template parameter to a `constexpr` function with `template <auto member_ptr>`.
      That function returns `__PRETTY_FUNCTION__` or some other vendor specific macro that prints the whole name of a function
      along with the template arguments.
    * The returned value from previous step contains the member name ([@https://godbolt.org/z/K4aWdcE9G godbolt example]). Do some
      compiler specific parsing of the value and make a `std::string_view` that contains only the member name.
# at run-time: return the `std::string_view` with the member name.

[endsect]

[section Acknowledgements]

Many thanks to Bruno Dutra for showing the technique to precisely reflect aggregate initializable type in C++14 [@https://github.com/boostorg/pfr/issues/5 Manual type registering/structured bindings might be unnecessary].

Many thanks to Alexandr Poltavsky for initial implementation the [*BOOST_PFR_USE_LOOPHOLE == 1] technique and for describing it [@http://alexpolt.github.io/type-loophole.html in his blog].

Many thanks to Chris Beck for implementing the detect-offsets-and-get-field-address functionality that avoids Undefined Behavior of reinterpret_casting layout compatible structures.

Many thanks to the Boost people who participated in the formal review, especially to Benedek Thaler, Steven Watanabe and Andrzej Krzemienski.

[endsect]

[xinclude autodoc_pfr.xml]
