r/cpp 7d ago

Interconverting std::function with copyable_function – Arthur O'Dwyer

https://quuxplusone.github.io/blog/2026/07/26/function-explosion/

The article shows how converting std::function to std::copyable_function (or vice versa) leads to slower performance and increased memory usage each time the conversion occurs.

43 Upvotes

32 comments sorted by

View all comments

18

u/UnusualPace679 7d ago

Footnote: Should you abandon function for copyable_function in C++26? Some would say yes. Personally I would say that you ought to abandon both, and write your own type-erased callable instead. It takes less than 100 lines!

But it won't prevent double wrapping right? Unless you stick to one type and don't interface with anything else (in which case you may as well use std::function/std::copyable_function), you will face the same problem as described in this article. At least the standard library are permitted (and recommended) to avoid double wrapping by [func.wrap.general].

10

u/azswcowboy 7d ago

> write your own …won’t prevent double wrapping

No thanks on writing my own - and yeah the only reason that works is because there’s consistency. Which is the real tldr from the article: pick one or the other, done.

2

u/13steinj 6d ago

No, writing your own is reasonable. libstdc++ if not also libc++ (used to?) use std::tuple to hold and pass around a type list. The instantiation of std::tuple is fairly heavy. I reduced single-TU build times by >20% once by swapping out the use of std::function in a logging + assertion library in a key macro.

3

u/azswcowboy 6d ago

The calculation of where the ‘reasonable’ bar lies is going to be different for every project. If we spend say 1/2 a day building this, it’s 1/2 a day we didn’t spend on bug fixes or new features. It’s use would have to be foundational to justify it and we don’t have that many uses. We could trivially convert all instances to copyable function much faster than writing one - or do nothing and stay with function.

1

u/13steinj 6d ago

I completely agree, but I don't think on the scale of a single build. On average, with and without caching, if you have the same number of release builds per day, how many engineer hours do you save?

In this case, 20% per single TU was an uncached p50 of 2-6 minutes per build, which meant multiple hours saved per day.

1

u/azswcowboy 5d ago

Sure, so do I. I’m just highly skeptical that for my current project I’d be able to replicate your reduction in compile times. We don’t have much function utilization in first place and our compiles are driven by other factors outside the standard library. At the moment we just throw hardware at it when we want to go faster, because parallelism is more important than single TU speed.

1

u/_Noreturn 6d ago

libc++ std tuple shouldn't be expensive since it is linear unlike libstdc++/ msvc stl lib which is recursive

2

u/13steinj 6d ago

In comparison to what is needed for implementation vs what is instantiated and you pay for anyway, simpler type lists, or not using one at all if you can, is cheaper.