Как 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();
}

Godbolt ссылка

1 ответ

Вот мое понимание:

Аргументы по умолчанию заменяются на месте вызова и оцениваются при каждом вызове. См. Следующий код в качестве примера:

#include <iostream>

int count() {
    static int counter = 0;
    return ++counter;
}

void foo(int value = count())
{
    std::cout << value << "\n";
}

int main()
{
   foo();
   foo();
}

Смотрите в Godbolt

На выходе

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)

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