The 2011 C++ standard introduced the new keyword auto
, which can be used for defining variables instead of a type, i.e.
auto p=make_pair(1,2.5); // pair<int,double>
auto i=std::begin(c), end=std::end(c); // decltype(std::begin(c))
In the second line, i
and end
are of the same type, referred to as auto
. The standard does not allow
auto i=std::begin(container), e=std::end(container), x=*i;
when x
would be of different type. My question: why does the standard not allow this last line? It could be allowed by interpreting auto
not as representing some to-be-decuded type, but as indicating that the type of any variable declared auto
shall be deduced from its assigned value. Is there any good reason for the C++11 standard to not follow this approach?
There is actually a use case for this, namely in the initialisation statement of for
loops:
for(auto i=std::begin(c), end=std::end(c), x=*i; i!=end; ++i, x+=*i)
{ ... }
when the scope of the variables i
, end
, and x
is limited to the for
loop. AFAIK, this cannot be achieved in C++ unless those variables have a common type. Is this correct? (ugly tricks of putting all types inside a struct
excluded)
There may also be use cases in some variadic template applications.
I think it's just a matter of consistency with non-auto
declarations.
This:
auto n = 42, *p = &n;
is equivalent to:
int n = 42, *p = &n;
where the types int
and int*
are derived from the initializers. In both cases, even though int
and int*
are different types, they're permitted to be in the same declaration because of their close syntactic relation. (By the "declaration follows use" rule that C and C++ declarations almost follow, you're defining both n
and *p
as being of type int
.)
It would have been possible to permit unrelated types in the same declaration:
auto n = 42, x = 1.5;
but the above would have to be equivalent to two separate declarations:
int n = 42; double x = 1.5;
I think the idea when adding auto
was to make a minimal change to the language, permitting the type to be inferred from an initializer but not changing the kinds of declarations that are possible.
Even without auto
, you could define an int
and an int*
in a for
loop header:
for (int n = 42, *p = &n; expr1; expr2) { /* ... / }
but you couldn't declare an int
and a double
together. The addition of auto
simply didn't change that.
Outside the context of a for
loop, it's generally much better to use separate declarations anyway. Shoving a lot of different declarations into a for
loop is arguably a bad idea in most cases. And for the (probably rare) cases where you want a lot of declarations, you can just put them above the loop, something like this:
auto i=std::begin(c), end=std::end(c),
for( x=*i; i!=end; ++i, x+=*i) {
// ...
}
adding another set of {
}
around the whole thing if you want to limit the scope. (In this case, you'd probably want end
to be const
anyway.)