Boost logo

Boost :

Subject: Re: [boost] [Fit] Purpose and Use Cases
From: Paul Fultz II (pfultz2_at_[hidden])
Date: 2016-02-16 19:39:47

> It isn't clear to me from the documentation what are the real world use

Well, I go over some simple use cases in quick start guide, maybe its not
entirely clear. As the Fit library is a collection of generic utilities
related to functions, there is many useful cases with the library, but a key
point of many of these utilities is that they can solve these problems with
much simpler constructs than whats traditionally been done with


The `BOOST_FIT_STATIC_FUNCTION` will help initialize function objects at
global scope, and will ensure that it is initialized at compile-time and (on
platforms that support it) will have a unique address across translation
units, thereby reducing executable bloat and potential ODR violations.

In addition, `BOOST_FIT_STATIC_LAMBDA_FUNCTION` allows initializing a lambda
in the same manner. This allows for simple and compact function definitions
when working with generic lambdas and function adaptors.

Of course, the library can still be used without requiring global function
objects for those who prefer to avoid them will still find the library

Conditional overloading

Take a look at this example of defining a `stringify` function from
stackoverflow here:

The user would like to write `stringify` to call `to_string` where
and fallback on using `sstream` ot convert to a string. Most of the top
answers usually involve some amount of metaprogramming using either `void_t`
or `is_detected`. However, with the Fit library it can simply be written

BOOST_FIT_STATIC_LAMBDA_FUNCTION(stringify) = conditional(
    [](auto x) BOOST_FIT_RETURNS(to_string(x)),
    [](auto x)
BOOST_FIT_RETURNS(static_cast<ostringstream&>(ostringstream() << x).str())

In addition, this can be used with `fit::if_` to create static if-like
constructs. For example, Baptiste Wicht discusses how one could write static
if in C++ here:

He wants to be able to write this:

template<typename T>
void decrement_kindof(T& value){
    static_if(std::is_same<std::string, T>::value){
    } else {

However, that isn't possible in C++. With the Fit library one can simply

template<typename T>
void decrement_kindof(T& value)
        if_(std::is_same<std::string, T>())([&](auto id){
        [&](auto id){

The advantage of using the Fit library instead of the solution in Baptiste
Wicht's blog is `conditional` allows more than just two conditions. So if
there was another trait to be checked, such as `is_stack`, it could be
like this:

template<typename T>
void decrement_kindof(T& value)
        if_(is_stack<T>())([&](auto id){
        if_(std::is_same<std::string, T>())([&](auto id){
        [&](auto id){

Furthermore, this technique can be used to write type traits as well. Jens
Weller was looking for a way to define a general purpose detection for
operands(such as `*` and `->`). One way to accomplish this is using Fit like

template<class T>
auto has_pointer_member(const T&) -> decltype(

BOOST_FIT_STATIC_LAMBDA_FUNCTION(has_pointer_operators) = conditional(
    [](auto* x) -> -> bool_constant<(!std::is_void<decltype(*x)>())>,

template<class T>
struct is_dereferenceable
: decltype(has_pointer_operators(std::declval<T>()))

Which is much simpler than the other implementations that were written(it
about 3 times the amount of code):


Instead of writing the projection multiple times in algorithms:

std::sort(std::begin(people), std::end(people),
          [](const Person& a, const Person& b) {
            return a.year_of_birth < b.year_of_birth;

We can use the `by` adaptor to project `year_of_birth` on the comparison

std::sort(std::begin(people), std::end(people),
        by(&Person::year_of_birth, _ < _));

Ordering evaluation of arguments

When we write `f(foo(), bar())` there is no guarantee from the standard what
order the arguments `foo()` and `bar()` are evaluated. So with `apply_eval`
can order them from left-to-right:

apply_eval(f, [&]{ return foo(); }, [&]{ return bar(); });

Varidiac parameters

As shown in the guide the `by` adaptor can be used to apply a function to
argument, so we could write a simple varidiac print function like this:

BOOST_FIT_STATIC_FUNCTION(print) = by(std::cout << _);

We can also take binary functions and turn them easily into varidiac
as well using `compress`. So a varidiac `max` function could be written like

BOOST_FIT_STATIC_FUNCTION(max) = compress(BOOST_FIT_LIFT(std::max));

Polymorphic constructors

Writing polymorphic constructors(such as `make_tuple`) is a boilerplate that
has to be written over and over again for template classes. With `construct`
this is easier. For example, `make_tuple` can be written simply as this:

BOOST_FIT_STATIC_FUNCTION(make_tuple) = construct<std::tuple>().by(decay());

Extension methods

Chaining many function together, like what is done for range based libraries
can make things hard to read:

auto r = transform(
        [](int x) { return x > 2; }
    [](int x) { return x * x; }

It would be nice to write this:

auto r = numbers
    .filter([](int x) { return x > 2; })
    .transform([](int x) { return x * x; });

However, UFCS in C++17 won't allow this to be done generically. So instead
pipable functions can be used. So it can be written like this:

auto r = numbers
    | filter([](int x) { return x > 2; })
    | transform([](int x) { return x * x; });

Now, if some users feel a little worried about overloading the bit or
operator, pipable functions can also be used with flow like this:

auto r = flow(
    filter([](int x) { return x > 2; }),
    transform([](int x) { return x * x; })

No fancy or confusing operating overloading and everything is still quite

> What can't be done today (for example composition) with simple C++11

First, its not a replacement for lambdas, but rather it builds on top of
lambdas(and function objects) in C++, especially in C++14.

Some of the limitations of lambdas in C++11 of course, is that they are not
generic, and they don't support constexpr(not even in C++14). The Fit
provides a small lambda emulation using the `lazy` adaptor(like what is done
with `std::bind` or Boost.Lambda) with the main purpose to support some
`constexpr` lambda expressions. Of course, it is not a full emulation like
what is done in Boost.Lambda or Boost.Phoenix. However, I have found that in
practice emulated-lambda expressions are generally only useful for small
simple expressions.

> I'd love to see several real world examples and use cases of Boost.FIT
> because at least for me I don't really understand why it is useful.

Well hopeful between this and the quick start guide, you can see some of the
usefulness of the library. Let me know if you have more questions.


Boost list run by bdawes at, gregod at, cpdaniel at, john at