This is a really important question to me as it's a bottleneck right now and I'm trying to investigate possible ways to solve my problem: I need to constexpr construct a std::function-like class that I am using that is quite simple. However, it's using aligned storage so that we can configure a pointer-sized number of captured elements. Let's call it Function.
https://github.com/fwsGonzo/libriscv/blob/master/lib/libriscv/util/function.hpp#L91
Specifically, I am using Function with up to 1 pointer captured. Usually "this". These functions are working wonderfully, and they will not compile if you try to capture too much.
The problem is that they have to be constructed at run-time, and there are so many of them that they are using around 3500 nanoseconds (3.5 micros), which is an eternity for my use case. I absolutely have to find a way to reduce this setup cost somehow, so the natural way to do that would be to investigate if I can construct them at compile-time.
I've been unable to do so and the compiler outright tells me that the constructor which uses placement new cannot be used in a constexpr context. This question tells the same story:
C++ constexpr in place aligned storage construction
You can see the problematic statement here: https://github.com/fwsGonzo/libriscv/blob/master/lib/libriscv/util/function.hpp#L148
template<typename Callable>
Function (Callable callable) noexcept
{
static_assert(sizeof(Callable) <= FunctionStorageSize,
"Callable too large (greater than FunctionStorageSize)");
static_assert(std::is_trivially_copy_constructible_v<Callable>,
"Callable not trivially copy constructible");
static_assert(std::is_trivially_destructible_v<Callable>,
"Callable not trivially destructible");
m_func_ptr = &trampoline<Callable>;
new(reinterpret_cast<Callable *>(m_storage.data)) Callable(callable);
}
I am using C++20 and I am open to suggestions on how to solve this. Given that these functions have a constant-sized capture storage with a single function pointer, is it possible to construct these at compile time somehow? No heap allocations should result from this.