【问题标题】:How does consteval influence evaluation of default arguments?consteval 如何影响默认参数的评估?
【发布时间】:2020-10-19 15:18:57
【问题描述】:

在下面的代码中,如果here() 不再是consteval(完整的RT 或constexpr),那么line()f()main() 内的调用行。但是constevalf() 的定义。这种差异从何而来?

#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 link

【问题讨论】:

  • 在调用站点替换默认参数(如果使用)。如果表达式已经被 constevaled,那么无论调用站点如何,它都将具有相同的值,可以说?因为不同的翻译单元可能会调用相同的f 函数。这将松散/不好地解释为什么,但我同意这会令人惊讶。
  • 请务必注意,您正在尝试执行的操作(将 source_location::current 替换为与之等效的内容)不起作用。这个函数假定总是返回source_location::current所在的代码位置,而不是调用它的位置any 调用here 的正确答案应该是第 4 行。没有办法让您尝试做的工作;您必须从您希望获取当前位置的位置准确调用该函数。
  • 根据我自己的实验,GCC 尚未很好地实现源位置。 consteval 与否,您可能会发现报告的源代码行的变体。
  • @NicolBolas,试试godlink,将consteval 替换为constexpr(或完全删除)并查看变化。现在here() 变成source_location::current() 的别名——我的理解是它发生因为 a = here() 在调用f() 时被评估,而f() 又在同一个地方评估loc = source_location::current() ,然后使用来自少数内置的内在“函数”的值评估 current() 的所有默认参数。
  • @Oliv,GCC/Clang __builtin_FILE/_FUNCTION/_LINE 已经存在一段时间了,source_location::current 是一种标准化它们的方式...

标签: c++ constexpr c++20 consteval


【解决方案1】:

这是我的理解:

默认参数在调用站点替换并在每次调用时进行评估。 以如下代码为例:

#include <iostream>

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

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

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

See in godbolt

输出是

1
2

这证明count() 被调用了两次,而main() 正文实际上等效于:

foo(count());
foo(count());

现在让我们回到您的示例。当here() 不是consteval 时,您对f() 的调用等效于f(here()),而f(here()) 又等效于f(here(std::experimental::source_location::current())),这将返回对f() 的调用行,即@987654334 @。

但是,如果here()consteval,当编译器读取f() 的声明时,它必须立即计算here(),它返回某个std::experimental::source_location,此时其line() 等于10 (为了解释的目的,我们称之为default_location),因此当你调用f()时,默认参数已经被评估为default_location,并且调用实际上相当于f(default_location)

【讨论】:

  • 您建议的default_location 的值至少可以说是古怪的。请参阅修改后的Godbolt,其中有两个不同的函数使用consteval 默认初始化程序——它们是在函数的(声明?定义?)位置计算的——见我的f()g()例子,然后是非constevalline()h(),它使用它并且具有更多预期的结果/副作用......
  • 是的,因为编译器看到f()的定义(我想你是对的,它是一个定义),看到默认参数是here(),但是here()consteval ,所以它必须立即评估它,所以默认参数实际上变成了13而不是here()g() 也是如此,默认参数立即被评估为 19 而不是 here()。然而对于函数h()line() 不是consteval,所以它没有理由立即评估它,并将line() 本身作为默认参数。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-10-06
  • 2019-09-20
  • 2010-11-24
  • 1970-01-01
  • 2010-12-11
  • 1970-01-01
相关资源
最近更新 更多