问题
Why doesn't defining a variable with auto
keyword carry the constexpr
'ness of the expression used to initialize it?
As an example, consider the following code:
#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(); }
With GCC 10.2 and --std=c++20 -fsanitize=undefined -O3
, this compiles into:
foo():
mov eax, 3
ret
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.
Notes:
- I marked this question C++20, but I have no reason to believe this behavior is different from C++11's.
- This question is not about the example, it is about the general behavior of
auto
w.r.t.constexpr
ness. The example simply shows that that GCC does not treat x asconstexpr
if we don't explicitly tell it to.
回答1:
auto
is intended to enable type deduction, not a replacement for "everything useful you would have typed here". constexpr
is not a part of an expression's type, and is thus ignored by auto
(as opposed to const
and volatile
, which are part of an expression's type, and are deduced).
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.
That is a choice for your compiler. It has 100% of the information it needs to make that code go away. The fact that it didn't is not the C++ standard's concern.
This is a "quality of implementation" issue, not a standardization issue. If an implementation won't run as much of your code at compile-time as you desire, you can complain to them about it.
Remember: constexpr
isn't meant to be a runtime optimization per-se. It's meant to allow you to write things that you otherwise couldn't write. Like std::get<g()>(some_tuple)
or whatever. That code has to run at compile-time, since it's being used in a template parameter.
I'm not asking about some kind of deep deduction, only about the case of the function explicitly being constexpr.
Let's forget for a moment that auto
is for type deduction and constexpr
is not part of the type system. Let's focus instead on what if auto
was supposed to deduce constexpr
anyway. So what you want is for auto
to only deduce constexpr
if <expr>
is specifically a function that is designated constexpr
.
So let's look at some code:
auto x = constexpr_func();
auto y = constexpr_func() + 5;
auto z = constexpr_func() + constexpr_func();
auto w = constexpr_func_2() + constexpr_func_2();
Which of these variables are constexpr
? If what you want is what we had, then x
would be constexpr
, but y
would not. I personally would find this both surprising and annoying.
Worse, if we assume constexpr_func()
returns an int
, then z
is also not constexpr
. But if constexpr_func_2()
returns a user-defined literal type that has a constexpr operator+
, then w
would be constexpr
.
Isn't that all very weird? So I highly suspect that this is not what you really want.
What you really want is for auto x = <expr>;
to deduce constexpr
if constexpr auto x = <expr>;
would be valid.
But really, that goes back to the original point. If you make a variable constexpr
, that should mean you want it to be used in a place where being constexpr
is required by some process. Given that fact, deducing constexpr
makes no sense, because you should need it to be constexpr
lest you get a compile error.
来源:https://stackoverflow.com/questions/64500142/why-does-auto-not-adopt-the-constexprness-of-its-initializing-expression