为什么 `auto` 不采用其初始化表达式的constexpr'ness?

Why does `auto` not adopt the constexpr'ness of its initializing expression?

为什么用 auto 关键字定义的变量不带有用于初始化它的表达式的 constexpr'ness?


例如,考虑以下代码:

#include <string_view>

constexpr std::string_view f() { return "hello"; }

static constexpr std::string_view g() {
    constexpr auto x = f(); // (*)
    return x.substr(1, 3);
}

int foo() { return g().length(); }

使用 GCC 10.2 和 --std=c++20 -fsanitize=undefined -O3,这个 compiles 变成:

foo():
        mov     eax, 3
        ret

但是如果我们去掉第 (*) 行的 constexpr,我们将得到一个 27 行的程序,其中包含一堆指针、一个长字符串常量等。

备注:

auto 旨在启用类型推导,而不是替代“您在此处输入的所有有用内容”。 constexpr 不是表达式类型的一部分,因此被 auto 忽略(与 constvolatile 相反,它们是表达式类型的一部分,并且是推导)。


But if we remove the constexpr on line (*), we would get a 27-line program with a bunch of pointers, a long string constant etc.

这是您的编译器的选择。它拥有使该代码消失所需的 100% 的信息。它没有的事实与 C++ 标准无关。

这是一个“实施质量”问题,而不是标准化问题。如果一个实现不会 运行 你的代码在 compile-time 上如你所愿,你可以向他们投诉。

记住:constexpr 并不意味着 运行 时间优化 per-se。它旨在让您能够写出您原本无法写出的东西。像 std::get<g()>(some_tuple) 之类的。该代码 必须 运行 在 compile-time,因为它在模板参数中使用。


I'm not asking about some kind of deep deduction, only about the case of the function explicitly being constexpr.

让我们暂时忘记 auto 用于类型推导而 constexpr 不是类型系统的一部分。让我们转而关注如果 auto 无论如何都应该推断出 constexpr 会怎样。所以你想要的是 auto 只有 推导 constexpr 如果 <expr> 是专门指定的函数 constexpr.

让我们看一些代码:

auto x = constexpr_func();
auto y = constexpr_func() + 5;
auto z = constexpr_func() + constexpr_func();
auto w = constexpr_func_2() + constexpr_func_2();

这些变量中的哪些是 constexpr?如果您想要的是我们拥有的,那么 x 将是 constexpr,但 y 不会。我个人会觉得这既令人惊讶又令人讨厌。

更糟糕的是,如果我们假设 constexpr_func() returns 和 int,那么 z 也不是 constexpr。但是,如果 constexpr_func_2() returns 具有 constexpr operator+ 的 user-defined 文字类型,则 w 将是 constexpr.

这一切是不是很奇怪?所以我高度怀疑这不是你真正想要的。

你真正想要的是 auto x = <expr>; 推导出 constexpr 如果 constexpr auto x = <expr>; 有效。

但实际上,这又回到了原点。如果你创建一个变量 constexpr,那应该意味着你希望它被用在某个过程需要 constexpr 的地方。鉴于这一事实,推断 constexpr 没有任何意义,因为您应该 需要 它是 constexpr 以免出现编译错误。