why auto i = same_const_variable could not deduce “const”?

半城伤御伤魂 提交于 2019-12-01 21:22:01
Praetorian

auto mostly follows the same type deduction rules as template argument deduction. The only difference is that auto will deduce std::initializer_list from a braced-init-list in some cases, while template argument deduction doesn't do this.

From N3337, §7.1.6.4 [dcl.spec.auto]

6   ... The type deduced for the variable d is then the deduced A determined using the rules of template argument deduction from a function call (14.8.2.1), ...

The behavior you're observing is the same as what template argument deduction would do when deducing types from a function call

§14.8.2.1 [temp.deduct.call]

2   If P is not a reference type:
    — ...
    — If A is a cv-qualified type, the top level cv-qualifiers of A’s type are ignored for type deduction.

Thus, in

auto i = ci;

the top level const qualifier is ignored and i is deduced as int.

When you write

auto& i = ci;

then i is no longer not a reference type and the above rule doesn't apply, so the const qualifier is retained.

auto by itself means that you want a new, locally-owned variable with a copy of the given value. const-ness is not part of value. An int is an int whether it's specified using a literal, a named constant, an expression, or a non-const variable.

auto i = 3,
     j = i,
     k = ci,
     m = 3 + 4; // All these variables are type int.

To get a constant of deduced type, you can still use auto const. This expresses within the declaration how the variable may be used.

const auto i = 3;

Since C++14, there is also the decltype(auto) specifier which applies decltype to the initializer, to make a carbon copy of the given variable. Perhaps that's really what you expected:

decltype(auto) i = ci; // i receives type const int.

Live demo.

decltype(auto) is a bit tricky, though, and it has few use cases aside from its original purpose relating to deciding the return type of function call wrappers. Unless there's a good reason, choose const auto or const int instead.

Another alternative is to use a forwarding reference, spelled auto &&. This refers to the variable or value that initializes it, whatever that may be.

auto && i = ci; // i receives type const int & and aliases ci.

This is less expressive and specific, but reliably declares i as an alias to ci. The other thing you tried was auto &, which is similar but only allows forming a reference to a preexisting variable.

auto & i = ci; // i receives type const int & and aliases ci.

A reference to a const int variable must be of type const int &, because otherwise it would permit illegal modification.

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