3

I mean, why the following example is not a valid construction:

if (auto x = 2, y = "ab"; x != 0) {
  // ...
}

(In my real use case there are calls to some functions instead of 2 and "ab" literals.)

or

std::vector<int> cont1;
std::vector<char> cont2;
for (auto it1 = cont1.begin(), it2 = cont2.begin(); it1 != cont1.end() && it2 != cont2.end(); ++it1, ++it2) {
  // ...
}

It seems that e.g. in the first example, Visual C++ deduces int for auto from the first 2 and then it reports: "ab" cannot initialize int.

But on the other side it is allowed to write:

if (auto [x, y] = std::make_pair(2, "ab"); x != 0) {
  // ...
}

So here, auto stands for different types.

Beside the answer "why", I'd like to know if there are any other workarounds (except the one I have above).

Nicol Bolas
  • 378,677
  • 53
  • 635
  • 829
Jarek C
  • 892
  • 5
  • 16
  • 1
    "*So here, auto stands for different types.*" No, it "stands for" one type: the type returned by `std::make_pair`. `x` and `y` are subobjects of that object. – Nicol Bolas May 17 '21 at 16:05
  • @largest_prime_is_463035818 Is that strictly speaking true? I can't write the actual type of `auto func = [](){return 0;};` but `auto` still deduces whatever implementation-defined type the lambda expression is. – Nathan Pierson May 17 '21 at 16:08
  • Reason is history. When `auto` has been introduced in `C++11` it suppose to replace single type, not a multiple types. later in C++17 `auto [x, y] = tuple` was introduced to easier handle tuples and tuples only. – Marek R May 17 '21 at 16:09
  • @NathanPierson you are absolutely right. `auto` did have a great impact and without lambdas would not be what they are and thats not the only example. comment deleted – 463035818_is_not_a_number May 17 '21 at 16:16
  • 1
    it is really not about `auto`, different types in initialization statement are just not allowed `int x = 0, const char *y = "asd"; ...` - https://stackoverflow.com/questions/2687392/is-it-possible-to-declare-two-variables-of-different-types-in-a-for-loop – dewaffled May 17 '21 at 16:16

2 Answers2

4

So here, auto stands for different types.

I wouldn't interpret it that way.

The auto stands for std::pair<int, char const*>. However, the special thing here is that the name of the pair is [a, b], where a and b refer to the inner members of the pair. I would really like if the language would allow typing the type of the pair explicitly.

In fact, a and b are not variables. They are structured bindings, and they behave a bit differently. Although that difference is getting less apparent in C++20.

So really, the auto here is only one type.

Another way to demonstrate my point is this:

int x = 0, y = 0;
auto [a, b] = std::tie(x, y);

Even though it was auto and not auto&, a and b are references to x and y. And attempting to use auto& won't work since the result of std::tie is a prvalue.


However, there are places where only one auto might refer to different things.

Consider this:

auto lambda = [](auto... args) { /* ... */ };

Here, auto... is many different things, but auto... is different than auto.

Guillaume Racicot
  • 32,627
  • 7
  • 60
  • 103
  • Thanks for valuable comments (especially diff between variables and structured bindings). With this I could understand why this: `int x; auto a = x, *b = &x;` works. Here `auto` stands for `int` and all around works "as usually". – Jarek C May 17 '21 at 18:56
  • 1
    @JarekC that''s because C++ uses C notation for type modifiers, where pointer, reference, array notation is technically part of the name of the variable. It's quite confusing and I usually only declare one variable per statements because of that. – Guillaume Racicot May 17 '21 at 19:06
2

For auto to work, compiler needs to be able to deduce the type of the variable without you telling it explicitly.

When you write foo x,y you are telling compiler that variables x and y are both of type foo.

When you write auto a,b you are telling the compiler that it should deduce variables a and b to the same type. But compiler doesn't do implicit casting in such situation. Thus you cannot use auto even when it could make logical sense (e.g. auto a = 2.0, b = 2;).

Allowing for different types, when such syntax usually explicitly requests same type could lead to serious bugs.


Also, auto [x, y] = std::make_pair(2, "ab") - here auto doesn't stand for different types. auto gets deduced to be a pair of intiger and string.

Jorengarenar
  • 1,821
  • 1
  • 7
  • 22