Document number P0792R1
Date 2017-11-26
Reply-to Vittorio Romeo <>
Audience Library Evolution Working Group
Project ISO JTC1/SC22/WG21: Programming Language C++

function_ref: a non-owning reference to a Callable


This paper proposes the addition of function_ref<R(Args...)> to the Standard Library, a “vocabulary type” for non-owning references to Callable objects.

Changelog and polls

From P0792R0 to P0792R1


Semantics: pointer versus reference

option 1

function_ref, non-nullable, not default constructible

option 2

function_ptr, nullable, default constructible

We want 1 and 2


1 2 8 3 6

ref vs ptr


6 5 2 5 0

The poll above clearly shows that the desired direction for function_ref is towards a non nullable, non default-constructible reference type. This revision (P0792R2) removes the “empty state” and default constructibility from the proposed function_ref. If those semantics are required by users, they can trivially wrap function_ref into an std::optional<function_ref</* ... */>>.

target and target_type

We want target and target-type (consistent with std::function) if they have no overhead

Unanimous consent

We want target and target-type (consistent with std::function) even though they have overhead


0 0 1 9 4

I am not sure whether target and target_type can be implemented without introducing overhead. I seek the guidance of the committee or any interested reader to figure that out. If they require overhead, I agree with the poll: they will be left out of the proposal.

Table of contents


Since the advent of C++11 writing more functional code has become easier: functional programming patterns and idioms have become powerful additions to the C++ developer’s toolbox. “Higher-order functions” are one of the key ideas of the functional paradigm - in short, they are functions that take functions as arguments and/or return functions as results.

The need of referring to an existing Callable object comes up often when writing functional C++ code, but the Standard Library unfortunately doesn’t provide a flexible facility that allows to do so. Let’s consider the existing utilities:

This paper proposes the introduction of a new function_ref class template, which is akin to std::string_view. This paper describes function_ref as a non-owning lightweight wrapper over any Callable object.

Motivating example

Here’s one example use case that benefits from higher-order functions: a retry(n, f) function that attempts to synchronously call f up to n times until success. This example might model the real-world scenario of repeatedly querying a flaky web service.

struct payload { /* ... */ };

// Repeatedly invokes `action` up to `times` repetitions.
// Immediately returns if `action` returns a valid `payload`.
// Returns `std::nullopt` otherwise.
std::optional<payload> retry(std::size_t times, /* ????? */ action);

The passed-in action should be a Callable which takes no arguments and returns std::optional<payload>. Let’s see how retry can be implemented with various techniques:

Impact on the Standard

This proposal is a pure library extension. It does not require changes to any existing part of the Standard.


The only existing viable alternative to function_ref currently is std::function + std::reference_wrapper. The Standard guarantees that when a std::reference_wrapper is used to construct/assign to a std::function no allocations will occur and no exceptions will be thrown.

Using std::function for non-owning references is suboptimal for various reasons.

  1. The ownership semantics of a std::function are unclear - they change depending on whether or not the std::function was constructed/assigned with a std::reference_wrapper.

    void foo(std::function<void()> f);
    // `f` could be referring to an existing Callable, or could own one.
    void bar(function_ref<void()> f);
    // `f` unambiguously is a non-owning reference to an existing Callable.
  2. This technique doesn’t work with temporaries. This is a huge drawback as it prevents stateful temporary lambdas from being passed as callbacks.

    void foo(std::function<void()> f);
    int main()
        int x = 0;
        foo(std::ref([&x]{ ++x; }); // does not compile

    The code above doesn’t compile, as std::ref only accepts non-const lvalue references (additionally, std::cref is explicitly deleted for rvalue references). Avoiding the use of std::ref breaks the guarantee that f won’t allocate or throw an exception on construction.

  3. std::function is harder for compilers to optimize compared to the proposed function_ref. This is true due to various reasons:

    Rough benchmarks comparing the generated assembly of a std::function parameter and a function_ref parameter against a template parameter show that:

    A description of the benchmarking techniques used and the full results can be found on my article “passing functions to functions” 1.


namespace std
    template <typename Signature>
    class function_ref
        constexpr function_ref(const function_ref&) noexcept;

        template <typename F>
        constexpr function_ref(F&&);

        constexpr function_ref& operator=(const function_ref&) noexcept;

        template <typename F>
        constexpr function_ref& operator=(F&&);

        constexpr void swap(function_ref&) noexcept;

        R operator()(Args...) qualifiers;
        // `R`, `Args...`, and `qualifiers` are the return type, the parameter-type-list,
        // and the sequence "cv-qualifier-seq-opt noexcept-specifier-opt" of the function
        // type `Signature`, respectively.

    template <typename Signature>
    constexpr void swap(function_ref<Signature>&, function_ref<Signature>&) noexcept;

    template <typename R, typename... Args>
    function_ref(R (*)(Args...)) -> function_ref<R(Args...)>;

    template <typename R, typename... Args>
    function_ref(R (*)(Args...) noexcept) -> function_ref<R(Args...) noexcept>;

    template <typename F>
    function_ref(F&&) -> function_ref<see below>;

The template argument Signature shall be a non-volatile-qualified function type.

<functional> header

Add the following to [functional.syn]:

namespace std
    // ...

    template <typename Signature> class function_ref;

    template <typename Signature>
    constexpr void swap(function_ref<Signature>& lhs, function_ref<Signature>& rhs) noexcept;

    // ...


template <typename Signature>
constexpr function_ref<Signature>::function_ref(const function_ref& rhs) noexcept;

template <typename Signature>
template <typename F>
constexpr function_ref<Signature>::function_ref(F&& f);

template <typename Signature>
constexpr function_ref& function_ref<Signature>::operator=(const function_ref& rhs) noexcept;

template <typename Signature>
template <typename F>
constexpr function_ref& function_ref<Signature>::operator=(F&&);

template <typename Signature>
constexpr void function_ref<Signature>::swap(function_ref& rhs) noexcept;

template <typename Signature>
R function_ref<Signature>::operator()(Args... xs) qualifiers;

template <typename F>
function_ref(F&&) -> function_ref<see below>;

template <typename Signature>
constexpr void swap(function_ref<Signature>& lhs, function_ref<Signature>& rhs) noexcept;

Feature test macro

I propose the feature-testing macro name __cpp_lib_function_ref.

Example implementation

An example implementation is available here on GitHub.

Existing practice

Many facilities similar to function_ref exist and are widely used in large codebases. Here are some examples:

Additionally, combining results from GitHub searches (excluding “llvm” and “folly”) for “function_ref10, “function_view11, “FunctionRef12, and “FunctionView13 roughly shows more than 2800 occurrences.

Possible issues

Accepting temporaries in function_ref’s constructor is extremely useful in the most common use case: using it as a function parameter:

void foo(function_ref<void()>);

int main()
    foo([]{ });

The usage shown above is completely safe: the temporary closure generated by the lambda expression is guarantee to live for the entirety of the call to foo. Unfortunately, this also means that the following code snippet will result in undefined behavior:

int main()
    function_ref<void()> f{[]{ }};
    // ...
    f(); // undefined behavior

The above closure is a temporary whose lifetime ends after the function_ref constructor call. The function_ref will store an address to a “dead” closure - invoking it will produce undefined behavior 14. As an example, AddressSanitizer detects an invalid memory access in this gist 15. Note that this problem is not unique to function_ref: the recently standardized std::string_view 16 has the same problem 17.

I strongly believe that accepting temporaries is a “necessary evil” for both function_ref and std::string_view, as it enables countless valid use cases. The problem of dangling references has been always present in the language - a more general solution like Herb Sutter and Neil Macintosh’s lifetime tracking 18 would prevent mistakes without limiting the usefulness of view/reference classes.

Open questions

Below are some unanswered questions for which I kindly ask guidance from members of the commitee and readers of this paper.


The name function_ref is subject to bikeshedding. Here are some other potential names:


Thanks to Agustín Bergé, Dietmar Kühl, Eric Niebler, Tim van Deurzen, and Alisdair Meredith for providing very valuable feedback on earlier drafts of this proposal.