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

ein*_*ica 0 c++ type-inference constexpr auto c++20

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


例如,请考虑以下代码:

#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(); }
Run Code Online (Sandbox Code Playgroud)

使用 GCC 10.2 和--std=c++20 -fsanitize=undefined -O3编译为:

foo():
        mov     eax, 3
        ret
Run Code Online (Sandbox Code Playgroud)

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

笔记:

  • 我将此问题标记为 C++20,但我没有理由相信这种行为与 C++11 不同。
  • 这个问题与示例无关,而是关于autowrt constexprness的一般行为。该示例只是表明 GCC 不会将 x 视为constexpr我们没有明确告诉它。

Nic*_*las 5

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


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

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

这是一个“实施质量”问题,而不是标准化问题。如果一个实现在编译时没有按照你的意愿运行尽可能多的代码,你可以向他们抱怨。

请记住:constexpr本身并不意味着运行时优化。它的目的是让你写出你无法写的东西。喜欢std::get<g()>(some_tuple)什么的。该代码必须在编译时运行,因为它在模板参数中使用。


我不是在问某种深度推论,只是问函数明确为 constexpr 的情况。

让我们暂时忘记它auto是用于类型推导而constexpr不是类型系统的一部分。让我们转而关注 if无论如何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();
Run Code Online (Sandbox Code Playgroud)

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

更糟糕的是,如果我们假设constexpr_func()返回一个int,那么z也不是constexpr。但是,如果constexpr_func_2()回报率,有一个用户定义的文本类型constexpr operator+,然后w constexpr

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

您真正想要的是auto x = <expr>;推断constexpr是否constexpr auto x = <expr>;有效。

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

  • @einpoklum 考虑一下您建议的“auto a = 0;”和“int b = 0;”的不同行为,以及如果“a”突然变成“constexpr”,会破坏多少代码。 (2认同)