Подтвердить что ты не робот

Почему не std:: algorithms constexpr и что может быть?

Почему нет методов std::algorithm constexpr? Если я правильно понимаю новые правила С++ 14, многие из этих методов могут быть constexpr. Например, почему не может std::find быть constexpr?

static constexpr std::array<char, 4> DnaBases {'A', 'C', 'G', 'T'};

constexpr bool is_dna(char b)
{
    return std::find(std::cbegin(DnaBases), std::cend(DnaBases), b) != std::cend(DnaBases); // why not?
}

Какой другой std::algorithm может быть constexpr?

4b9b3361

Ответ 1

Это может быть constexpr, но не может быть оценено как константное выражение, так как в этом случае, например, для поиска во время компиляции требуется, чтобы: begin/end должен быть constexpr, * operator итератора должен быть constexpr, operator == должен быть constexpr, operator !=, поскольку итератор должен быть constexpr, operator ++, поскольку итератор должен быть constexpr. Но если все функции constexpr, то многие алгоритмы могут быть реализованы с помощью constexpr.

Вы можете посмотреть библиотеку SPROUT для реализации контейнеров/алгоритмов constexpr.

И связанный разговор на форумах isocpp.org

Ответ 2

Функции не могут быть перегружены на основе constexpr -ness. В результате любая функция, определенная как constexpr, должна быть реализована в форме, которая может быть constexpr. Это требование накладывает ограничения на все реализации.

Спецификация С++ 14 несколько смягчена относительно ограничений по сравнению с С++ 11. Однако, когда спецификация была завершена, никто не был уверен, что все оптимизации, которые могут быть достигнуты без ограничения constexpr, могут быть достигнуты, когда алгоритмы должны быть constexpr. Не зная, что функциональность не constexpr не мешает выполнению реализаций constexpr, алгоритмы не будут определены как constexpr. Использование алгоритмов не constexpr по-прежнему считается основным использованием алгоритмов.

Возможно, стоит иметь специальный набор алгоритмов, которые определены как constexpr. Я не знаю подходящего предложения. Я также не вижу многого, если спрос требует стандартизации, но мое восприятие может отличаться от других.

Ответ 3

Текущая (С++ 14) стандартная библиотека в значительной степени недоступна w.r.t. к соответствующим возможностям основного языка в отношении constexpr.

Например, MSVC 2015, который поддерживает только язык С++ 11 для constexpr, мог почти полностью реализовать использование стандартной библиотеки С++ 14 constexpr. Единственными исключениями были std::min, std::max, std::minmax, std::min_element, std::max_element, std::minmax_element для std::initializer_list.

С С++ 1z (17?) алгоритмы std::xxx_element станут constexpr алгоритмами для общего итератора и входов компаратора, чтобы унифицировать использование для std::initializer_list. Кроме того, существуют предложения для constexpr lambda для С++ 1z.

При обновлении lambdas все еще осталось несколько ограничений для основного языка, чтобы предотвратить заголовок <algorithm> всего constexpr. (Имейте в виду, что это не технологические препятствия, а большинство из них могут быть разрешены, позволяя компилятору оценить их).

  • Некоторые алгоритмы могут динамически распределять память, вызывая std::get_temporary_buffer (std::inplace_merge, std::stable_sort и std::stable_partition), что недопустимо в контекстах constexpr.
  • Некоторые алгоритмы могут вернуться к низкоуровневым подпрограммам C, таким как memset (std::fill и std::fill_n), что помешало бы авторам библиотек использовать эти алгоритмы в контекстах constexpr.
  • Некоторые реализации алгоритмов могут извлечь выгоду из разумного использования goto (например, std::nth_element, std::stable_sort), для которого C++1z предложение было отклонено.
  • И последнее, но не менее важное: constexpr - это изменение интерфейса, обещая, что все будущие реализации должны будут выполнить это обещание. По этой причине реализациям не разрешается добавлять constexpr в качестве функции качества выполнения (в отличие от noexcept).

В частности, четвертый вопрос останавливает эксперименты с тем, насколько constexpr может быть нажата для стандартной библиотеки (алгоритмы, контейнеры и другие утилиты). Вместо этого отдельное предложение должно быть написано и одобрено для каждого расширения constexpr.

Ответ 4

std::algorithm алгоритмы действуют на итераторы. Существует техническая причина, по которой их constexpr обычно либо предотвращает их компиляцию (в С++ 11), либо ничего не делает (в С++ 14 или с условным constexpr), но также есть семантическая причина, по которой это не имеет смысла для них быть constexpr.

Техническая причина заключается в том, что функции constexpr не могут вызывать выражения не constexpr. ForEveR указывает, что функции шаблона constexpr не могут быть вычислены во время компиляции, если они вызывают выражения не constexpr.

В случае std::algorithm оценка функций constexpr в std::algorithm потребует, чтобы функции доступа к итераторам контейнеров были constexpr, что в свою очередь потребовало бы, чтобы итераторы были типами constexpr. Но это невозможно почти по определению; контейнеры обычно проектируются как облегченный доступ к памяти, выделенной кучей, но память кучи не может быть выделена во время компиляции (конечно). В приведенных ниже комментариях dyp указывает, что итераторы не всегда указывают на контейнеры, но даже эти итераторы вряд ли будут использоваться во время компиляции; например, объекты потоков, конечно, не читаются или записываются во время компиляции, так как IO не может быть выполнено во время компиляции.

Это приводит к семантической проблеме: constexpr семантически означает, что функция должна быть оценена во время компиляции. Объявление условных функций constexpr, когда невозможно оценить их во время компиляции, сделает API запутывающим и вводящим в заблуждение.

Теперь, , я думаю, что язык был бы улучшен, если бы существовал способ создания и использования контейнеров во время компиляции; это сделало бы constexpr более похожим на возможности макроса Lisp. В конечном итоге это может быть добавлено, но в настоящее время оно не поддерживается существующим стандартным библиотечным кодом. Самый гибкий подход, позволяющий некоторым объектам жить в куче во время компиляции, как уже упоминалось выше, вообще не поддерживается основным языком, и это создаст серьезные осложнения. Например, что было бы законным делать с такими объектами? Либо их продолжительность жизни должна быть ограничена только временем компиляции, либо они должны быть включены как статическая память const в финальной программе (например, строковый литерал) или... что?