4

I don't understand why this doesn't work:

auto a = (int[]){1, 2, 3, 4, 5};

> error: taking address of temporary array

I understand that array lvalues decay to pointers when converted to rvalues but here the array is already an rvalue (actually a prvalue) so no decay should be needed. I would have expected a to be deduced and initialized to int[5]. Why is it trying to take the address of a temporary?

xskxzr
  • 12,442
  • 12
  • 37
  • 77
Sir Visto
  • 683
  • 1
  • 4
  • 9
  • I'm watching for an answer, but. [This](https://stackoverflow.com/questions/16949016/how-to-declare-array-with-auto) may be relevant as auto can't do that. – lakeweb Feb 14 '19 at 18:05
  • This grammar is [ill-formed](https://gcc.godbolt.org/z/iFGbmN). – xskxzr Feb 14 '19 at 18:13

1 Answers1

5

I would have expected a to be deduced and initialized to int[5]

Sadly, this is not how C arrays work. Arrays decays into pointers. You cannot really have an "array value". If you replace auto by the deduced type, it looks like this:

int* a = (int[]){1, 2, 3, 4, 5};

The decay must take the address to make the pointer.

This is easily fixed by using references, since reference to temporaries extends their lifetime:

auto&& a = (int[]){1, 2, 3, 4, 5}; // works!

Here's the example running on compiler explorer.

Of course, with std::array you get a nice syntax and value semantics:

auto a = std::array{1, 2, 3, 4, 5};
Guillaume Racicot
  • 39,621
  • 9
  • 77
  • 141
  • `auto a = (const int[]){1, 2, 3, 4, 5};` should also work. – Unimportant Feb 14 '19 at 18:23
  • Hi @Unimportant , I get the same compiler error with vs141, even with the constant. – lakeweb Feb 14 '19 at 18:30
  • @lakeweb Perhaps vs141 does not allow compound literals, which are strictly speaking not supported by C++. gcc allows them (but will warn when compiled with `-pedantic`). That's a separate issue from the storage issue in the question. – Unimportant Feb 14 '19 at 18:35
  • 1
    I don't get your agumentation chain. `std::is_same_v` returns true and `std::is_same_v` returns false, so why `auto a = (int[]){1, 2, 3, 4, 5};` should be the same as `int* a = (int[])(1, 2, 3, 4, 5);`? I can't find the line in the draft which found your theses. Since `int[5]` is an aggregate type at least `auto a = (int[5]){1, 2, 3, 4, 5};` should work... I mean `auto aggregate = (A){1, 2, 3, 4, 5};` is also wroking for each aggregate type A with 5 int members. – JulianW Feb 14 '19 at 18:37
  • Hi @Unimportant , yes, this is not the first time I've run into gcc allowing something not c++ and where Microsoft just stays strict about it. Thanks. – lakeweb Feb 14 '19 at 19:00
  • "Arrays decays into pointers". Decay "happens when an lvalue expression is used as an rvalue" (http://www.cplusplus.com/reference/type_traits/decay/). But here the array is already an rvalue, so there should be no decay... – Sir Visto Feb 15 '19 at 09:54
  • @SirVisto I wouldn't treat cpluslus.com as ground truth. The standard is always more precise. You could ask a question with the `language-lawyer` tag, but this one is quite easy. Decays always happen, whether you have r-value or l-value. Here's [an expample](https://godbolt.org/z/2GYvXM). – Guillaume Racicot Feb 15 '19 at 12:58
  • @Guillaume: That's not quite the same: (int[]){1, 2, 3, 4, 5} is a true rvalue (prvalue), whereas int arr[5] = {1, 2, 3, 4, 5}; std::move(arr) gives an rvalue reference (xvalue), which needs to be de-referenced, which is when decay could occur. For the former case, it seems odd to have a prvalue magically convert to another prvalue - but then, C++ array behaviour is odd anyway. – Sir Visto Feb 15 '19 at 18:05
  • @SirVisto The thing is, decay is not influenced by R- or L- values. The text un cplusplus.com is misleading. I suggest not using that particular paragraph as reference. – Guillaume Racicot Feb 15 '19 at 18:13
  • @GuillaumeRacicot Your example has nothing to do with array-to-pointer conversion, auto placeholder deduction does the same as template argument deduction. Since `std::move(arr)` has type `int (&&)[5]`, the type referred to, i.e., `int [5]`, is used for type deduction. That's what auto is deduced.In the function case, another function parameter type adjustment is performed – Tuff Contender Oct 16 '21 at 12:01