У меня есть следующий код:
#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); даже не будет оцениваться. Но ошибка говорит об обратном. Почему?
Кто-нибудь может подробно объяснить, что происходит?
Программа работает.
Так как результат зависит от уровня оптимизации, то тут либо УБ, либо ошибка компилятора, и моя ставка не на УБ.
Клангс согласен с вашим примером . После очистки clang работает нормально, и gcc жалуется на меньшее количество ошибок: godbolt.org/z/TvM99PjsG
Это странно, когда результат привязки к consexpr локальной переменной полностью заглушает ошибку , а в ваша версия gcc в порядке и clang coplains
Сообщено об ошибке GCC: gcc.gnu.org/bugzilla/show_bug.cgi?id=115583
вау, спасибо, что подали билет. и спасибо всем за внимание!





Это подтвержденная 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, вызов становится немедленным вызовом и, как и должно быть, оценивается постоянно.
-O3.