С++ 20 constexpr std::копирование оптимизаций для времени выполнения

cppreference.com говорит:

На практике реализации std::copy избегают многократных назначений и используют функции массового копирования, такие как std::memmove, если тип значения TriviallyCopyable

Однако на странице также говорится, что перегрузки, которые не принимают политику выполнения, будут constexpr начиная с С++ 20. Будет ли стандарт запрещать такую оптимизацию во время выполнения (поскольку std::memmove не является constexpr) или есть способ оптимизировать функции constexpr для времени выполнения?

Ответы

Ответ 1

Мы тоже можем съесть пирог и съесть его.

Давайте рассмотрим простейшую специализацию copy, которая копирует char s. В С++ 17 это может выглядеть так:

char* copy(char const* first, char const* last, char* d)
{
    memcpy(d, first, last - first);
    return d + (last - first);
}

Конечно, мы не можем просто добавить constexpr к этому, потому что memcpy не является функцией constexpr, это не сработает. Но это только не работает при постоянной оценке. Нам нужен способ условно использовать memcpy, если мы находимся во время выполнения.

У нас есть такая вещь в С++ 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);
    }
}

И теперь у нас есть алгоритм, который эффективно работает во время выполнения, но все еще работает во время оценки constexpr.


Примечание: это if (std::is_constant_evaluated()), никогда if constexpr (std::is_constant_evaluated()). Последнее эквивалентно if constexpr (true) { ... }. GCC 10.1 начнет предупреждение об этом ошибочном использовании.