Consteval влияет на то, как выражение в функции классифицируется/оценивается?

У меня есть следующий код:

#include <string_view>
#include <iostream>
#include <cstring>

consteval const char* compile_time_trim(const std::string_view& s) noexcept{
    return s.data() + s.find("/app/") + strlen("/app/");
}

constexpr const char* best_effort_trim(const std::string_view& s) noexcept{
    if consteval {
        return compile_time_trim(s);
    }
    else {
        return s.data();
    }
}

int main() {
    std::cout << best_effort_trim(__FILE__) << std::endl;
}

И GCC 14.1 выдал ошибку:

<source>: In function 'int main()':
<source>:19:34:   in 'constexpr' expansion of 'best_effort_trim(std::basic_string_view<char>(((const char*)"<source>")))'
<source>:11:33: error: call to consteval function 'compile_time_trim((* & s))' is not a constant expression
   11 |         return compile_time_trim(s);
      |                ~~~~~~~~~~~~~~~~~^~~
In file included from <source>:1:
<source>:19:34:   in 'constexpr' expansion of 'best_effort_trim(std::basic_string_view<char>(((const char*)"<source>")))'
<source>:11:33:   in 'constexpr' expansion of 'compile_time_trim((* & s))'
<source>:6:18:   in 'constexpr' expansion of '(& s)->std::basic_string_view<char>::data()'
/opt/compiler-explorer/gcc-14.1.0/include/c++/14.1.0/string_view:290:22: error: '*(const std::basic_string_view<char>*)this' is not a constant expression
  290 |       { return this->_M_str; }
      |                ~~~~~~^~~~~~
Compiler returned: 1

Однако, если я изменю constexpr const char* best_effort_trim( на consteval const char* best_effort_trim(, GCC не выдаст ошибки.

Хотя макрос __FILE__ является константой времени компиляции, но кажется, что если его передать в функцию constexpr, s будет рассматриваться как неконстанта (даже если бы он мог быть создан во время компиляции), но почему?

Но если s считать непостоянным выражением, я подумал, что return compile_time_trim(s); даже не будет оцениваться. Но ошибка говорит об обратном. Почему?

Кто-нибудь может подробно объяснить, что происходит?

Никаких ошибок, если удалить -O3.
康桓瑋 21.06.2024 16:22

Программа работает.

user12002570 21.06.2024 16:30

Так как результат зависит от уровня оптимизации, то тут либо УБ, либо ошибка компилятора, и моя ставка не на УБ.

n. m. could be an AI 21.06.2024 17:22

Это странно, когда результат привязки к consexpr локальной переменной полностью заглушает ошибку , а в ваша версия gcc в порядке и clang coplains

Marek R 21.06.2024 18:31

Сообщено об ошибке GCC: gcc.gnu.org/bugzilla/show_bug.cgi?id=115583

Artyer 21.06.2024 18:41

вау, спасибо, что подали билет. и спасибо всем за внимание!

HCSF 22.06.2024 03:25
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
4
7
102
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Это подтвержденная GCC ошибка. return compile_time_trim(s); в вашем примере не должно выполняться.

GCC неправ, потому что блок if consteval выполняется тогда, когда этого не должно быть. [stmt.if] p5 гласит:

Если оператор consteval if оценивается в контексте, который явно оценивается константой, выполняется первый подоператор.

Этот термин определяется следующим образом:

Выражение или преобразование явно вычисляется с константой, если оно:

  • константное выражение или
  • условие оператора constexpr if ([stmt.if]), или
  • немедленный вызов или
  • результат подстановки в выражение атомарного ограничения, чтобы определить, удовлетворено ли оно ([temp.constr.atomic]), или
  • инициализатор переменной, которую можно использовать в константных выражениях или которая имеет константную инициализацию ([basic.start.static]).

В утверждении std::cout << best_effort_trim(__FILE__) << std::endl; ни одно из этих условий не выполняется, поэтому постоянной оценки не происходит. Ошибка, по-видимому, связана с тем, что GCC ошибочно выполняет постоянную оценку при включенной оптимизации; стандарт не допускает подобных произвольных константных оценок.

Когда вы меняете best_effort_trim на consteval, вызов становится немедленным вызовом и, как и должно быть, оценивается постоянно.

Другие вопросы по теме