Ответ 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 начнет предупреждение об этом ошибочном использовании.