Header lexy/callback/bind.hpp

Bind parameters of a callback or sink.

Placeholder lexy::values

lexy/callback/bind.hpp
namespace lexy
{
    constexpr auto values;
}

A placeholder that expands to all values produced by a rule unchanged.

In a bound call of the form bound[state](args…​), expands to args…​. The arguments are forwarded unchanged and in the same order. This happens in addition to any lexy::nth_value expansion.

Example 1. Emulate std::bind_front()
constexpr auto my_callback
    = lexy::callback<int>([](int factor, int i) { return factor * i; },
                          [](int factor, int a, int b) { return factor * (a + b); });

// Bind the first parameter and forward the rest unchanged.
constexpr auto bound = lexy::bind(my_callback, 2, lexy::values);

Placeholder lexy::nth_value

lexy/callback/bind.hpp
namespace lexy
{
    struct nth_value-impl
    {
        template <typename Fn>
        constexpr nth_value-impl map(Fn&& fn) const;

        template <typename Arg>
        constexpr nth_value-impl or_(Arg&& fallback) const;
        template <typename Arg>
        constexpr nth_value-impl operator||(Arg&& fallback) const;

        constexpr nth_value-impl or_default() const;
    };

    template <std::size_t N>
    constexpr nth_value-impl nth_value;

    inline namespace placeholders
    {
        constexpr auto _1 = nth_value<1>;
        
        constexpr auto _8 = nth_value<8>;
    }
}

A placeholder that expands to the Nth value produced by a rule.

In a bound call of the form bound[state](args…​), expands to the Nth argument (1-indexed). It is ill-formed if there are fewer than N arguments. For convenience, placeholders 1 through 8 are pre-defined.

The member function map() takes an invocable fn and returns a placeholder that expands to the transformed value. In a bound call of the form bound[state](args…​), expands to the std::invoke(fn, arg), where arg is the Nth argument.

The member function or_() or the operator|| overload (which can be invoked as lexy::_1 || fallback and lexy::_1 or fallback) take a fallback value and return a placeholder that expands to the Nth value or fallback. In a bound call of the form bound[state](args…​) with fewer than N arguments, expands to fallback. In a bound call of the form bound[state](args…​) where the Nth argument is of type lexy::nullopt, expands to fallback. Otherwise, expands to the Nth argument.

The member function or_default() returns a placeholder that expands to the Nth value or a default-constructed object. It is equivalent to or_() with a fallback value that is implicitly convertible to any other type by default constructing it.

map() and one of or_(), operator||, and or_default() can be combined. If that is the case, the fallback value is not transformed by fn but produced as specified.

Example 2. Reorder and map arguments
constexpr auto my_callback = lexy::callback<int>([](int a, int b) { return a - b; });

// Swap the arguments...
constexpr auto bound = lexy::bind(my_callback, lexy::_2,
                                  // ... and double the (old) first one.
                                  lexy::_1.map([](int i) { return 2 * i; }));
Example 3. Produce a different value from lexy::opt
struct decimal
{
    int         integer;
    std::string fraction;
};

struct production
{
    struct fraction
    {
        static constexpr auto rule  = dsl::capture(dsl::digits<>);
        static constexpr auto value = lexy::as_string<std::string>;
    };

    static constexpr auto rule = [] {
        auto integer = dsl::integer<int>(dsl::digits<>);

        return integer + dsl::opt(dsl::period >> dsl::p<fraction>);
    }();

    static constexpr auto value = lexy::bind(lexy::construct<decimal>,
                                             // If the second argument is lexy::nullopt,
                                             // produce a zero instead.
                                             lexy::_1, lexy::_2 or "0");
};

Placeholder lexy::parse_state

lexy/callback/bind.hpp
namespace lexy
{
    struct parse_state-impl
    {
        template <typename Fn>
        constexpr auto map(Fn&& fn) const;
    };

    constexpr parse_state-impl parse_state;
}

A placeholder that expands to the parse state.

In a bound call of the form bound[state](args…​), expands to state. It is ill-formed if no state was provided to the callback.

The member function map() takes an invocable fn and returns a placeholder that expands to the transformed parse state. In a bound call of the form bound[state](args…​), expands to the std::invoke(fn, state).

Example 4. Access additional state in a callback
struct entry
{
    std::string name;
    int         a, b;
};

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

    static constexpr auto rule = [] {
        auto integer = dsl::integer<int>(dsl::digits<>);
        return dsl::twice(integer, dsl::sep(dsl::comma));
    }();

    // Construct the entry where the name is taken from the parse state.
    static constexpr auto value
        = lexy::bind(lexy::construct<entry>, lexy::parse_state, lexy::values);
};

Callback lexy::bind

lexy/callback/bind.hpp
namespace lexy
{
    template <typename ... BoundArgs>
    constexpr callback auto bind(callback auto callback, BoundArgs&&... args);
}

Bind parameters or transform and reorder arguments of a callback.

When invoked as bound[state](args…​) it invokes callback with the bound arguments. If the bound argument is a placeholder, it is expanded as described there. Otherwise, the bound argument is forwarded as-is.

Example 5. Bind all parameters
constexpr auto my_callback
    = lexy::callback<int>([](int factor, int i) { return factor * i; },
                          [](int factor, int a, int b) { return factor * (a + b); });

// Bind all arguments.
constexpr auto bound = lexy::bind(my_callback, 2, 11);
Caution
Arguments to the bound callback are silently discarded if they’re not needed by a placeholder.

Sink lexy::bind_sink

lexy/callback/bind.hpp
namespace lexy
{
    template <typename ... SinkArgs, typename ... BoundArgs>
    constexpr sink<> auto bind_sink(sink<SinkArgs...> auto sink, BoundArgs&&... args);
}

Bind parameters of the .sink() member function.

It returns a sink whose sink() member function forwards to sink and returns the same sink callback. However, sink.sink() is invoked by the bound arguments.

A call to bound.sink() results in a call to sink.sink(args…​), where no argument must be a placeholder. A call to bound.sink(state) results in a call to sink.sink() with the expanded arguments: If the argument is a placeholder, it is expanded as described there but note that there are no values, only a state parameter. Otherwise, the bound argument is forwarded as-is.

A call to bound(…​) will be forwarded as-is onto sink(…​), allowing a bound sink to be used with rules like opt_list from lexy::dsl::terminator.

Example 6. Construct the list of integers with a custom allocator
struct state
{
    std::allocator<int> allocator; // The allocator that should be used.
    // Potentially other members here.
};

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

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

    static constexpr auto value
        // Pass the allocator to the sink.
        // Note: this is the same as the `.allocator(&state::allocator)`.
        = lexy::bind_sink(lexy::as_list<std::vector<int>>,
                          lexy::parse_state.map(&state::allocator));
};
Tip
Specifically for passing allocators to lexy::as_list or lexy::as_collection, use its .allocator() function instead. This also uses the allocator if used as a callback.
Note
The bound arguments must either be constants or lexy::parse_state; other placeholder make no sense as the call does not have any values.

See also