We can have our cake and eat it to, too.
Let’s just consider the simplest specialization of copy
, the one that copies char
s. In C++17, that might look like:
char* copy(char const* first, char const* last, char* d)
{
memcpy(d, first, last - first);
return d + (last - first);
}
Of course, we can’t just slap constexpr
on that because memcpy
isn’t a constexpr function, that won’t work. But it only doesn’t work during constant evaluation. What we need is a way to conditionally use memcpy
if we’re at runtime.
We have such a thing in C++20, std::is_constant_evaluated()
:
constexpr char* copy(char const* first, char const* last, char* d)
{
if (std::is_constant_evaluated()) {
while (first != last) {
*d++ = *first++;
}
return d;
} else {
memcpy(d, first, last - first);
return d + (last - first);
}
}
And now we have an algorithm that does the efficient thing at runtime but still works during constexpr evaluation time.
Note: It is if (std::is_constant_evaluated())
, never if constexpr (std::is_constant_evaluated())
. The later is equivalent to if constexpr (true) { ... }
. gcc 10.1 will start warning on this erroneous usage.