Discrimination When Using auto specifier to deduce the type of a Prvalue in C++

Viewed 103

I am trying to understand why the C++ standard/compiler discriminates against the behavior of auto. The example that I have is as follows:

int main()
{
    
    const int i = 34;//top level const on rhs. i is const int
    const auto &p = i;// low level const on rhs. p is const int&
    
    
    auto &g = i;//g is const int& . In this case the compiler is able to deduce that only reference to const can be bound to a const int 
    
    //auto &k = 5;//but in this case the compiler is not able(allowed) to deduce that only a reference to const can be bound to a prvalue 
    
    return 0;
}

As seen in the above code example, the compiler is able/allowed to deduce the type of variable g since only a reference to const type can be bound to a const type whereas in the next case the compiler is not able to deduce the type of variable k even though only a reference to const type can be bound to a const type. Ofcourse a rvalue reference can also be bound to a prvalue or xvalue.

My question is that even though we have a lvalue reference to some auto deduced type then why is the C++ standard does not allow the compiler to deduce k as const int& just as in the case of variable g? This seems intuitive enough to me. Maybe there are some problems associated with this which any of you can tell me.

I know that top level const of the initializer are ignored. For example,

const int i = 5;
auto k = i; //k is deduced to be int because the top level const of the initializer i is ignored

My question is about the implicit addition/deduction of the low level const on the rhs.

1 Answers

The reason why

auto &k = 5;

is not compilable is the same reason for which the following is not compilable

template<typename T>
void f(T&) {}

int main() {
    f(5);
}

So if the question is why can't auto be deduced as const int? in the first snippet, that question translates to why can't T be deduced as const int? in the second snippet.

Well, the rules¹ say that the type of the expression that you pass to f, in this case int because 5 is int (and there's no const going on here), is pattern-matched against the type of the parameter, which is T&, to determine T. So the only possibility is that T be int, and therefore the parameter's type is int&.

But a int& parameter can't be passed an rvalue such as 5, and this has nothing to do with type deduction. Indeed, the error that Clang gives for f(5) above is

candidate function [with T = int] not viable: expects an lvalue for 1st argument

So there's no smart thing as "can I add a const to make this valid?" going on.

Compare the above with the reason why const is deduced here:

const int i = 34;
auto &g = i;

Well, again, you can map the second statement to f(i) with the f I defined above. In this case, the expressions (i) is of type const int (not int as the 5), so when T&is pattern-matched against it, T is deduced as const int.


¹ I'm referring to Item 1 from Effective Modern C++ by Scott Meyers.

Related