Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++20 constexpr std::copy optimizations for run-time

cppreference.com says:

In practice, implementations of std::copy avoid multiple assignments and use bulk copy functions such as std::memmove if the value type is TriviallyCopyable

However, the page also states that the overloads which don't take an execution policy will be constexpr since C++20. Will the standard forbid these run-time optimizations (since std::memmove is not constexpr) or is there a way to optimize constexpr functions for run-time?

like image 690
Jakub Klinkovský Avatar asked Aug 22 '19 12:08

Jakub Klinkovský


1 Answers

We can have our cake and eat it to, too.

Let's just consider the simplest specialization of copy, the one that copies chars. 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.

like image 193
Barry Avatar answered Oct 21 '22 09:10

Barry