为什么 `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 行的程序,其中包含一堆指针、一个长字符串常量等。
备注:
- 我将此问题标记为 C++20,但我没有理由相信此行为与 C++11 的不同。
- 这个问题不是关于例子的,它是关于
auto
w.r.t的一般行为。 constexpr
性。这个例子简单地表明,如果我们没有明确告诉它,GCC 不会将 x 视为 constexpr
。
auto
旨在启用类型推导,而不是替代“您在此处输入的所有有用内容”。 constexpr
不是表达式类型的一部分,因此被 auto
忽略(与 const
和 volatile
相反,它们是表达式类型的一部分,并且是推导)。
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
以免出现编译错误。
为什么用 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 行的程序,其中包含一堆指针、一个长字符串常量等。
备注:
- 我将此问题标记为 C++20,但我没有理由相信此行为与 C++11 的不同。
- 这个问题不是关于例子的,它是关于
auto
w.r.t的一般行为。constexpr
性。这个例子简单地表明,如果我们没有明确告诉它,GCC 不会将 x 视为constexpr
。
auto
旨在启用类型推导,而不是替代“您在此处输入的所有有用内容”。 constexpr
不是表达式类型的一部分,因此被 auto
忽略(与 const
和 volatile
相反,它们是表达式类型的一部分,并且是推导)。
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
以免出现编译错误。