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

孤人 提交于 2021-02-20 04:23:05

问题


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. constexprness. The example simply shows that that GCC does not treat x as constexpr 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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!