Как consteval влияет на оценку аргументов по умолчанию?
В приведенном ниже коде, если here()
перестает быть consteval
(либо полное RT, либо constexpr
), тогда line()
это линия призыва f()
внутри main()
. Но сconsteval
это определение f()
. Откуда это несоответствие?
#include <experimental/source_location>
#include <iostream>
consteval std::experimental::source_location here(
std::experimental::source_location loc = std::experimental::source_location::current())
{
return loc;
}
void f(const std::experimental::source_location& a = here())
{
std::cout << a.line() << std::endl; // will either print 17, or 10
}
int main()
{
f();
}
1 ответ
Вот мое понимание:
Аргументы по умолчанию заменяются на месте вызова и оцениваются при каждом вызове. См. Следующий код в качестве примера:
#include <iostream>
int count() {
static int counter = 0;
return ++counter;
}
void foo(int value = count())
{
std::cout << value << "\n";
}
int main()
{
foo();
foo();
}
На выходе
1
2
Что доказывает count()
был вызван дважды, и main()
body фактически эквивалентно:
foo(count());
foo(count());
А теперь вернемся к вашему примеру. когдаhere()
не является consteval
, затем ваш звонок f()
эквивалентно f(here())
что, в свою очередь, эквивалентно f(here(std::experimental::source_location::current()))
и это вернет линию вызова к f()
, который 17
.
Однако если here()
является consteval
, когда компилятор читает объявление f()
, он должен немедленно оценить here()
который возвращает определенный std::experimental::source_location
чья line()
равно 10
в этот момент (назовем это default_location
для объяснения), поэтому, когда вы звоните f()
, аргумент по умолчанию уже оценивается как default_location
, и вызов фактически эквивалентен f(default_location)