Header lexy/callback/composition.hpp

Compose callbacks and sinks.

Callback lexy::operator|

namespace lexy
    constexpr callback auto operator|(callback auto first, callback auto second);

Composes two callbacks.

The result is a callback that forwards all arguments to first, then forwards that result to second. If either first or second is a callback with a state argument, the result is as well and it will forward the state.

Example 1. Compose two callbacks
constexpr auto my_strlen
    // Construct a string, then return its size.
    = lexy::as_string<std::string> | lexy::callback<std::size_t>(&std::string::size);

Callback and sink lexy::operator>>

namespace lexy
    template <typename ... Args>
    constexpr auto operator>>(sink<Args...> auto sink, callback auto callback);

Combines a sink and a callback.

The result is both a sink and a callback. As a sink, it forwards to the sink. As a callback, it forwards all arguments to callback. If the callback accepts a state, the result does as well and will forward it.

Example 2. Compose a sink and a callback
struct entry
    std::string      name;
    std::vector<int> numbers;

struct production
    static constexpr auto whitespace = dsl::ascii::space;

    static constexpr auto rule = [] {
        auto integer = dsl::integer<int>;
        return dsl::square_bracketed.list(integer, dsl::sep(dsl::comma));

    static constexpr auto value
        // Collect all the numbers in a vector, then turn the result into an entry.
        = lexy::as_list<std::vector<int>> >> lexy::callback<entry>([](std::vector<int>&& vec) {
              return entry{"foo", std::move(vec)};
If you have a production that produces both a list and some other values, using sink >> callback would work and the callback is called with the final list and the other values. However, it is better to split the list part into a separate production that needs only a sink. Use operator>> only if you need to post-process the result of a sink.