Library / SDK
Dobiasd/FunctionalPlus avatar
Dobiasd/FunctionalPlus

FunctionalPlus, a small header-only library of named C++ functions

Functional Programming Library for C++. Write concise and readable C++ code.

2,295 stars179 forksC++BSL-1.0

At a glance

What is it?
FunctionalPlus is a Boost-licensed, header-only C++ library built from pure functions that work on any container with a familiar interface, and its argument is not that it is more powerful than the standard library but that a named function tells you what a loop body would have told you only after reading it. The repository is unusually honest about this, shipping the README's performance examples as a compilable file and a benchmark against range-v3.
Who is it for?
Use FunctionalPlus when you are writing C++14 or C++17 against standard containers and find that your loops and iterator pairs are drowning the intent, and when you want the change to be a single header include with nothing to build. Do not adopt it expecting a stable API, because the project is on a 0.2.x line, and do not adopt it for lazy evaluation, since its functions are eager and the difference from a range library is fundamental rather than stylistic.
Can I use it commercially?
Yes. BSL-1.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 18 days ago.
What is it written in?
Mainly C++, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 1, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What FunctionalPlus is, and the one thing it is not claiming

FunctionalPlus is a small header-only C++ library whose stated purpose is to help you write concise and readable C++ code. The README's framing is that while using C++ in practice you end up dealing with low-level things like iterators or hand-written loops that distract from the essence of the code, and that the library helps you reduce code noise and deal with only one single level of abstraction at a time.

That last phrase is the design brief, and it is narrower than the name suggests. This is not a general functional programming framework. There is no monad, no functor hierarchy, no typeclass emulation. It is a collection of pure, easy-to-use functions that implement commonly used flows of control so you do not implement them again, and every one of them is eager and returns a concrete container.

The README is careful to make its case without overclaiming, which is the first sign that the author has thought about how such a library is received. It sets up a concrete problem, a list of integers of which you want only the odd ones, and then gives three solutions. The first is a range-based for loop with a condition and a `push_back`. The second is `std::copy_if` from the standard library, which is the correct tool for the job. The third is `keep_if` from FunctionalPlus. It then says that if you think the third might be the most pleasant to work with, you might like this library, and invites you to consider what happens if the predicate were much longer.

That last point is the actual argument, and it is a good one. Reading `keep_if` tells you immediately that the result can only contain elements that came from the input and were selected by some predicate, however complicated. Reading the for loop tells you nothing until you have read the whole body, and the body is the part that grows. A comment at the top of the loop saying what the one-liner would have said for free is not a style preference, it is a maintenance cost paid on every future read.

None of this is more expressive than `std::copy_if`. It is a different answer to the question of where the meaning of a piece of code lives.

Container genericity is the decision everything else follows from

The README states that the functions shown work not only with the default standard containers such as `std::vector`, `std::list`, `std::deque` and `std::string`, but also with custom containers providing a similar interface.

That single sentence is more consequential than it looks, because it rules out the approach the standard library takes. An algorithm written against an iterator pair accepts anything iterable, and in exchange it loses the container: you pass `std::begin` and `std::end`, and the result comes back in whatever container you provided a back inserter for. The types on both sides of the call are unconstrained, which is exactly why `copy_if` reads as a slightly noisy version of `keep_if`.

A function that takes a container and returns a container can constrain both. If `keep_if` takes the container, the return type is a container of the same kind holding the same element type, and the compiler deduces it without you naming anything. The README has a section on type deduction and useful error messages, which is where this shows up: the library is designed so that in the common case you write one function name and a predicate and let the types follow.

The cost of that choice is the mirror image. Constraining on the container means a function that genuinely needs to work across heterogeneous iterators is awkward, and it means the library is operating one level above the standard algorithms rather than beside them. Whether that is right depends on the kind of code you write. In application code with vectors and maps everywhere, the container-generic form is much shorter. In generic library code where the input type is itself a template parameter, the standard iterator-pair form is often the only thing that compiles.

The examples in the README use explicit typedefs and explicit include of a single umbrella header, which is the ergonomic end of this design:

cpp
#include <fplus/fplus.hpp>
#include <iostream>

One include, then a function call. There is no build step, no library to link, and no configuration, which is the practical appeal of a header-only design at this size.

The function shapes on offer, from a predicate to a composed pipeline

The examples show a small number of recurring shapes, and it is worth naming them because they tell you what kind of code the library is meant to make shorter.

Property queries come first. `all_the_same` tests a container for a property across its elements, and the example prints a line when every string in a list matches. The other direction is `count` combined with `split_words`, which counts occurrences of a character across a tokenised string. Both are the kind of thing that becomes a five-line loop the moment you need it, and a one-liner the second time.

Projection is the second shape. The cat example defines a struct with a `cuteness` member function that multiplies five fields together and subtracts a sixth, then finds the highest rated element with:

cpp
auto cutest_cat = fplus::maximum_on(std::mem_fn(&cat::cuteness), cats);

`std::mem_fn` is doing real work there rather than being decoration. Passing a pointer to a member function as the projection means the same `maximum_on` works for a free function, a lambda, a bound function or a member function, and the type deduction section exists precisely to make those four cases behave. Without `mem_fn` this is the exact place where a template library turns into a template error, and the README's claim about useful error messages is a claim about this.

Composition is the third shape, and it is the one that goes furthest from the standard library. The Collatz example builds a pipeline out of pieces:

cpp
auto show_collats_seq = fplus::compose(collatz_seq, show_ints);
auto collatz_dict = fplus::create_map_with(show_collats_seq, xs);

`bind_1st_of_2` partially applies a separator to a container-showing function, `compose` chains a sequence generator to a formatter, and `create_map_with` applies the composed function across a range of keys to build a map. The result is a table of the Collatz sequence for every number below thirty, printed by indexing. Written by hand that is a nested loop, a temporary, a stringstream and a map insertion, and the intermediate variables would carry the meaning that `show_collats_seq` carries in its name.

The number generator closes the loop, with `fplus::numbers<Ints>(1, 30)` producing the keys. Taken together these four shapes, a predicate application, a property query, a projection and a composition, are what a functional library over eager containers actually needs. It is a much smaller surface than the standard library and it is aimed at a much more specific style of code.

The API search site is the project's homepage, which is the right call

The declared homepage of this repository is not a documentation site. It is a function search tool at a personal domain, and that choice says more about the library than any feature list could.

A header-only C++ library of this kind ships a few hundred named functions, most of which nobody will discover by reading a table of contents. The failure mode is not that the library lacks functionality. It is that a developer facing `std::accumulate`, `std::partial_sum` and `std::transform_executor` does not know that a fourth option exists, and therefore never looks. Documentation cannot fix that, because the problem is not finding the page, it is not knowing to start looking.

A search box over the function list does fix it, and it is the right shape of solution for a header-only library. Type the operation you want in words, get the function name, get the signature. That is a better interface for this problem than a categorised manual, and it is the interface the author has built for themselves first, which is usually why it works.

The repository supports the inference that the index is generated from the source rather than maintained by hand. There is a top-level directory named `api_search`, and there is a separate directory named `generate`, and the search site lives at the project's own domain rather than on a hosting platform. A hand-maintained index for a few hundred functions would drift within a release, and the README has a table of contents section on finding the functions you need, which is the documentation counterpart to the tool.

If you are evaluating whether the library is large enough to need this, the test is simple: count the functions in the search index. If it returns a few dozen results per query, the search is doing its job. If it returns two hundred for the word map, the library is at the point where a good naming convention and a search tool are both necessary, and this project has both.

The examples directory reinforces the same habit from a different direction. Alongside the general examples there is a file named `readme_perf_examples.cpp`, which is the README's performance examples as compilable code, and a file named `performance_range_v3.cpp`, which is the comparison as a benchmark you can run. A library that ships its own claims as a file you can build is making a different argument from one that asks you to trust a table.

include/, include_all_in_one/, and two package managers

The build and packaging surface of a header-only library is small, and this repository's is worth reading because it offers both the conventional layout and the convenience one.

The headers live in a top-level `include` directory, which is the standard place, and the entry point the examples use is `<fplus/fplus.hpp>`. Alongside that is a separate directory named `include_all_in_one`, which is the amalgamated form: one header containing everything, for projects that would rather not pay the cost of many small includes or that have a build system which makes large single files easier to handle.

Both forms are a real choice with a real trade-off. Many small headers compile faster in incremental builds, because a change to one function recompiles one translation unit's worth of header. One big header compiles the whole library on a clean build, which for a library this size is not a disaster, and it removes a class of include-order problems entirely. Offering both is a sign the author has thought about which users have which problem.

There is also an `all` directory at the top level, whose purpose is not described, and a `script` directory, which by name is either developer scripts or a scripting extension. Neither is described in the README, so the honest statement is that the tree contains more than the documentation explains.

Packaging goes through two routes. There is a `CMakeLists.txt` at the root with a `cmake` directory beside it, which is the conventional CMake integration and what a `find_package` consumer expects. There is also a `conanfile.txt`, which is a Conan recipe, so the library is available through a C++ package manager rather than only by vendoring the headers. Two routes is a reasonable amount of choice for a header-only library, and both are paths that avoid asking the user to copy a directory into their source tree.

One small entry deserves a mention because it is under-used: a `CITATION.cff` file at the top level. That is a citation metadata file in the format GitHub renders as a Cite button, and its presence means the project can be cited by an academic paper or a corporate writing-up without anyone inventing a citation format. For a library that has been used in production somewhere, that file is how the author finds out.

The `.clang-format` and `.clang-format-ignore` pair is the other detail worth naming. The project formats its own source with clang-format and keeps an ignore file for the files that must not be reformatted, which is the practice that keeps a large header-only library reviewable, since a diff that is only whitespace is a diff nobody reads.

BSL-1.0, a 0.2.x line, and quarterly releases

The licence is the Boost Software License 1.0, stated in the README with a badge and a link to the Boost licence text. It is a short permissive licence in the same family as MIT, requiring only that the licence text accompany source and binary distributions, and it is an unusual and slightly surprising choice for a C++ library that has nothing to do with Boost.

The reason is probably history. BSL-1.0 was written for the Boost libraries, and a C++ developer who has spent time in that ecosystem reaches for it by habit. There is no technical advantage over MIT and no real disadvantage either, so the choice is a matter of which permissive licence the author already had in mind. For an adopter it means the obligations are minimal: keep the licence text with what you distribute, and there is no copyleft obligation on code that links against it.

The version line is where a potential adopter should pause. The recent releases are v0.2.26 in October 2025, v0.2.27 in January 2026 and v0.2.28 in April 2026, which is roughly quarterly and consistent. But the project is still on 0.2.x, and under the convention most C++ projects follow, a zero major version means no API stability promise. A function signature can change between 0.2.27 and 0.2.28.

That is not an argument against using it. A header-only library that you vendor as a submodule can absorb a signature change in a commit, and the convenience of a single include with no build step is worth a great deal in exchange. It is an argument for vendoring rather than depending, and for reading the diff when you update rather than taking a tag and hoping.

The maintenance signal otherwise is good. The last push was on 2026-09-13, the repository is not archived, there is a CI badge wired to a workflow, a `CONTRIBUTING.md`, a dedicated `INSTALL.md` separate from the README, and a `test` directory. A library that keeps installation instructions in their own file rather than in a section of the README is a library whose users include people installing it on machines the author does not have, which is the case worth optimising for.

The last thing to say about the structure is that the examples directory contains a file called `99_problems.cpp`, which is the well-known Haskell exercise collection ported to C++. That is a good sign about how the library is meant to be learned. A functional library whose examples are all one-liners teaches you the function names. An exercise set teaches you the way of thinking, and that is the thing that transfers.

FunctionalPlus against the STL, against loops, and against range-v3

Three comparisons, and the third is the one the project itself takes seriously.

Against the standard library, FunctionalPlus is a convenience layer rather than an alternative. Nothing it does is unavailable in the standard library. What it changes is where the meaning of a line lives, which is the argument from the `keep_if` example, and the ergonomics of type deduction across the whole call. If your codebase already has a house style built on the standard algorithms, adding this library means two ways to do everything, which is a cost most teams will not accept.

Against hand-written loops, the comparison in the README is the fairest available and the project does not pretend to win unconditionally. The README explicitly says that if you still think the hand-written for loop is easier to understand, that is a reasonable position. The trade becomes decisive as the loop body grows, and a codebase that is mostly four-line loops may be better served by leaving them alone.

Against range-v3, the difference is architectural and not a matter of taste. range-v3 is a range library built around lazy views and expression templates, where a pipeline is a type that is assembled and then evaluated. FunctionalPlus is a set of eager functions that execute when called. A lazy pipeline over an infinite range is something FunctionalPlus cannot express, and the composition it offers, `compose` over functions, is not the same capability as composing lazy views over data. In exchange, FunctionalPlus's functions return concrete containers you can index and print immediately, which is what the Collatz example does with a map.

The comparison is not one-sided in the README's favour, and the project does not pretend it is. There is a comparison section in the table of contents, and there is a benchmark file in the examples directory named for range-v3, so the performance question is something the author expects to be asked and has made checkable. The content of that comparison is not shown in the README excerpt, and that section is the file to read before choosing, because a performance argument between two eager and lazy designs depends heavily on what you are doing with the result.

The honest summary is that FunctionalPlus is for a specific style: eager, container-generic, named operations on standard containers in application code. If that is your code, the library removes noise at a scale the standard library does not attempt. If your code is generic algorithms over iterators, or lazy transformations over unbounded data, it is the wrong shape of tool.

Editorial conclusion

Use FunctionalPlus when you are writing C++14 or C++17 against standard containers and find that your loops and iterator pairs are drowning the intent, and when you want the change to be a single header include with nothing to build. Do not adopt it expecting a stable API, because the project is on a 0.2.x line, and do not adopt it for lazy evaluation, since its functions are eager and the difference from a range library is fundamental rather than stylistic. Verify first by taking one loop from your own codebase and rewriting it as a call, then timing both, and by running the shipped examples/performance_range_v3.cpp to see the comparison on your own compiler and flags.

Frequently asked questions

What is FunctionalPlus?

It is a small header-only C++ library of pure, easy-to-use functions intended to reduce code noise and keep code at one single level of abstraction. The README frames it as helping you write concise and readable C++ rather than as adding power the standard library lacks, and the topic list records C++14 and C++17 support.

What licence is FunctionalPlus released under?

The Boost Software License 1.0, with a badge in the README linking to the Boost licence text and the file in the repository root. It is a short permissive licence in the same family as MIT, requiring that the licence text accompany source and binary distributions.

How do I install and use FunctionalPlus?

The repository has a dedicated INSTALL.md, a root CMakeLists.txt with a cmake directory, and a conanfile.txt, so it is consumable through CMake and through Conan. Headers are in an include directory, and the entry point used in the examples is <fplus/fplus.hpp>. An amalgamated single header is also provided in an include_all_in_one directory.

How do I find the right function in FunctionalPlus?

The project's homepage is a function search tool rather than a documentation site, and the README has a table of contents section on finding the functions you need. The repository contains an api_search directory and a generate directory, so the index appears to be produced from the source rather than maintained by hand.

How does FunctionalPlus compare to range-v3 and to the standard library?

The README has a dedicated comparison section and the repository ships examples/performance_range_v3.cpp, so the project benchmarks itself against range-v3. The architectural difference is eager functions returning containers against lazy range views, and against the standard library the change is where the meaning of a line lives rather than what is possible.

How often is FunctionalPlus released?

Roughly quarterly: v0.2.26 in October 2025, v0.2.27 in January 2026 and v0.2.28 in April 2026, with the last push on 2026-09-13. The project is still on a 0.2.x line, so there is no API stability promise, and vendoring the headers is safer than depending on a tag.

Official sources

  1. Dobiasd/FunctionalPlus on GitHub
  2. License: BSL-1.0
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/dobiasd-functionalplus.svg)](https://hysenlabs.com/projects/dobiasd-functionalplus)