constexpr с использованием стандартных библиотечных алгоритмов

#c #iterator #c 17 #constexpr #dereference

#c #итератор #c 17 #constexpr #разыменование

Вопрос:

При сборке с использованием C 17 / C 20 x64 gcc / clang приведенный ниже фрагмент выдает ошибку компиляции, тогда как отмена ссылки на итератор напрямую через *std::max_element(std::begin(arr), std::end(arr)) работает нормально. Есть идеи относительно того, почему? Я также наблюдал аналогичное поведение с другими стандартными алгоритмами, которые стали constexpr начиная с C 20, например std::upper_bound

 int main()
{
    constexpr std::array<int,5> arr = {1,2,3,4,5};
    constexpr auto it = std::max_element(std::begin(arr), std::end(arr));
}
 
 source>:11:73: error: '(((std::array<int, 5>::const_pointer)(amp; arr.std::array<int, 5>::_M_elems))   16)' is not a constant expression
   11 |     constexpr auto it  = std::max_element(std::begin(arr), std::end(arr));
      |           
 

Комментарии:

1. Итак, проблема, похоже, заключается в том, что if std::begin / std::end are constexpr , подается с помощью a constexpr std::array и std::max_element is constexpr , почему вывод не может быть слишком std::max_element ? constexpr

2. Особенно учитывая *std:max_element , что вывод constexpr

Ответ №1:

it должен хранить указатель на элемент arr .

Поскольку arr это не static так, он находится в стеке, поэтому его адрес не может быть определен во время компиляции.

Это будет работать, если вы сделаете arr static .

Комментарии:

1. Интересно, учитывая *std::max_element работы, предположительно, он рассматривает получение итератора и отмену ссылки на него как единое монолитное выражение, которое само по себе может быть constexpr.

2. @user3882729 Я не уверен, что я бы так сказал. std::max_element Вызов — это то, что может быть оценено во время компиляции «само по себе». Но значение, полученное в результате этой оценки, подлежит дальнейшим проверкам при попытке использовать его для инициализации constexpr переменной. Итератор, который имеет amp;arr «in», не передается, если arr не является static , но разыменованное значение является атомарным и проходит. Итератор «есть constexpr » в том смысле, что он разрешен как промежуточное звено в constexpr вычислениях, но не как результат.