| Home | Libraries | People | FAQ | More

## Tutorial

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

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.

### Accessing structure member by index

The following example shows how to access structure fields by index using `boost::pfr::get`.

Let's define some structure:

    #include <boost/pfr/core.hpp>

    struct foo {            // defining structure
        int some_integer;
        char c;
    };

We can access fields of that structure by index:

    foo f {777, '!'};
    auto& r1 = boost::pfr::get<0>(f); // accessing field with index 0, returns reference to `foo::some_integer`
    auto& r2 = boost::pfr::get<1>(f); // accessing field with index 1, returns reference to `foo::c`

### Custom printing of aggregates

The following example shows how to write your own io-manipulator for printing:

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

    namespace my_ns {

    /// Usage:
    ///     struct foo {std::uint8_t a, b;};
    ///     ...
    ///     std::cout << my_ns::my_io(foo{42, 22});
    ///
    /// Output: 42, 22
    template <class T>
    auto my_io(const T& value);

    namespace detail {
        // Helpers to print individual values
        template <class T>
        void print_each(std::ostream& out, const T& v) { out << v; }
        void print_each(std::ostream& out, std::uint8_t v) { out << static_cast<unsigned>(v); }
        void print_each(std::ostream& out, std::int8_t v) { out << static_cast<int>(v); }

        // Structure to keep a reference to value, that will be ostreamed lower
        template <class T>
        struct io_reference {
            const T& value;
        };

        // Output each field of io_reference::value
        template <class T>
        std::ostream& operator<<(std::ostream& out, io_reference<T>&& x) {
            const char* sep = "";

            boost::pfr::for_each_field(x.value, [&](const auto& v) {
                out << std::exchange(sep, ", ");
                detail::print_each(out, v);
            });
            return out;
        }
    }

    // Definition:
    template <class T>
    auto my_io(const T& value) {
        return detail::io_reference<T>{value};
    }

    } // namespace my_ns

### 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 26.1. 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
--- | --- | --- | --- | --- | --- | ---
`boost/pfr/ops.hpp: eq, ne, gt, lt, le, ge` `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
`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)
`boost/pfr/ops_fields.hpp: eq_fields, ne_fields, gt_fields, lt_fields, le_fields, ge_fields` `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`. `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.

### 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."

### Reflection of field name

Since C++20 it's possible to read name of a structure field by index using Boost.PFR library. The following example shows how to do it using `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 std::string_view n1 = boost::pfr::get_name<0, foo>(); // returns "some_integer"
    constexpr std::string_view n2 = boost::pfr::get_name<1, foo>(); // returns "c"

See Limitations and Configuration.