Why does C++ not allow multiple types in one auto statement?

我们两清 提交于 2019-12-01 02:49:58

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.)

According to the final revision of the accepted proposal for this feature, N1737,a possible multi-declarator auto implementation is as follows: (from Section 6)

We believe it is possible to achieve both consistent form and consistent behavior. We do so by inserting (for purposes of exposition) an intermediate __Deduced_type definition, and applying this type consistently in the as-if expansion:

  // Listing 12
 typedef int __Deduced_type; // exposition only
  __Deduced_type a = 1;
 // decltype(a) is int
 __Deduced_type b = 3.14; // decltype(b) is int
  __Deduced_type * c = new float; // error; decltype(c) would be int *

Not only do we achieve consistency of both form and behavior via such a reconciled formulation, we also address more complicated situations. For example, when the leading declarator includes a ptr-operator:

 // Listing 13 
auto * a = new int(1), b = 3.14, * c = new float;

our formulation attaches semantics as-if declared:

// Listing 14 
 typedef int __Deduced_type; // exposition only
 __Deduced_type * a = new int(1); // decltype(a) is int *
 __Deduced_type b = 3.14; // decltype(b) is int
 __Deduced_type * c = new float; // error; decltype(c) would be int *

As shown by this possible implementation, changing the type would be invalid, and as such would cause an error.
This feature was implemented this way because otherwise it would be different than other types of multi-variable declarations.
I remember seeing a discussion about whether or not to allow changing types, but I cannot remember where. IIRC, they decided that it would be harder to implement, but another reason could be that it was dropped because they could not come to a consensus on when to choose different types (the new behavior) or when to implicitly convert to the deduced type of the first declared variable (the old behavior).

If to refer to the C++ 2014 Working Draft then the Standard allows such code.Here is an example from the Standard Draft

auto x = 5, *y = &x; // OK: auto is int

I would like to append that in your example auto can not be dedused because iterator type and the value type of the iterator are two different types.

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