9

I don't see any logical reason. I mean you can easily overcome the requirement by using a structure containing an array member like this:

template <size_t n>
struct arr { int d[n]; };

auto fnReturningArray()
{
    return arr<3>{0, 1, 2};
};

Which will behave the exact same way as if the array is directly returned with the small difference that you should first access the structure member 'd' to use it. Also the standard itself have added similar functionality by the 'std::array' type. So it seems that it is implementation possible. Why then ISO C++ have forbidden this action? Maybe legacy code compatibility (but I can hardly believe this is the case as with the other new things added it is long gone, like for example the new meaning of the 'auto' keyword).

Ryan Haining
  • 35,360
  • 15
  • 114
  • 174
AnArrayOfFunctions
  • 3,452
  • 2
  • 29
  • 66
  • 7
    Because arrays cannot be copied. – Columbo Nov 23 '14 at 17:40
  • 3
    Arrays are not copyable or assignable, so you cannot return or pass them by value. As to why that is, well, that would be a good question. – juanchopanza Nov 23 '14 at 17:40
  • @Columbo But they became magically copyable when in struct. – AnArrayOfFunctions Nov 23 '14 at 17:51
  • 1
    Isn't that because arrays and pointers are effectively the same (and they are because of C compatibility)? So basically one should be able to use them interchangeably. – Nikolay Nov 23 '14 at 17:52
  • 10
    @Nikolay No, because they aren't, in either language. – molbdnilo Nov 23 '14 at 17:53
  • 12
    @Nikolay: Who told you that "arrays and pointers are effectively the same"? They were wrong. – Lightness Races in Orbit Nov 23 '14 at 17:55
  • I mean, if a function has a pointer argument for example, you can't tell from within, what it is - an array or just a pointer. – Nikolay Nov 23 '14 at 17:59
  • @Nikolay Because it is pointer, not an array. You can't know if a pointer points to an element in an array, but that is a different matter. – juanchopanza Nov 23 '14 at 18:01
  • 2
    @Nikolay: Yes you can. It is a pointer. What you can't do is tell how large is the block of memory to which it points. – Lightness Races in Orbit Nov 23 '14 at 18:16
  • 1
    Yes guys, it looks like the "auto-convert array to the pointer to first element" rule which I meant by "equivalence" does not prevent passing/returning arrays by value (so that's not the reason why it's not allowed in c++). Interesting duplicate discussion of the subject here (there is even an opinion that reason is heritage from "B" :) http://stackoverflow.com/questions/5157439/why-doesnt-c-support-functions-returning-arrays – Nikolay Nov 23 '14 at 18:56
  • An array is not a modifiable lvalue in C++. Which means an expression of `something = fnReturningArray()` is invalid, if the return value is actually an array type (e.g. of type `int [3]`). This is inherited from C, which also prevents returning an array by value (unless wrapped in a `struct` type or, in C++, a `struct` or `class` type, as noted in the question) – Peter Jul 28 '17 at 11:03
  • In short, avoid naked arrays and use the C++ mechanisms that handle vectors properly. You then will not be surprised by how badly native arrays are handled. – Michael Dorgan Jul 28 '17 at 18:54
  • 1
    The actual correct way to handle this (esp given you have tagged question C++14) is not to use a struct that wraps a C array, but just to use `std::array`. There's almost no reason to ever use C arrays in C++. – Nir Friedman Jul 28 '17 at 19:01

2 Answers2

2

Beside the fact that the standard doesn't allow it, and the historical reasons that could explain it, the issue is syntactic:

Imagine it would be permitted : how would you distinguish the naming of the whole array, vs the array address, vs a single element:

auto fnReturningArray()
{
    int a[3] = {0, 1, 2};
    return a;       // what is meant here ?  the address of the array ? or the whole array ?  
};

If you'd change the meaning of existing rules (such as tating that a would be the whole array), you would have huge problems with legacy code.

didierc
  • 14,572
  • 3
  • 32
  • 52
Christophe
  • 68,716
  • 7
  • 72
  • 138
  • 2
    Presumably you would have a rule that states that you're returning `int[3]`, because that is the type of `a`. If the language allowed to return arrays, then this would make perfect sense. You're using a circular argument here. – juanchopanza Nov 23 '14 at 17:55
  • 9
    That's easy: `a` is an array, so would mean you're returning an array. If you want a pointer to the first element, you'd write `&a[0]`. It's not how C++ works, but it would be a perfectly sensible language. –  Nov 23 '14 at 17:56
  • 1
    @hvd: But the fact that it's not how C++ works means it would be confusing/misleading/ambiguous syntax _in C++_ if added. – Lightness Races in Orbit Nov 23 '14 at 17:56
  • 7
    @LightnessRacesinOrbit I'm not saying that it would make sense to add it to C++ now, just that it would have made sense if that was how C++ (and perhaps even C) was designed from the start. –  Nov 23 '14 at 17:57
  • Clearly "int [3]". The most used type of arrays "int *" is created by implict cast. From [here](http://en.cppreference.com/w/cpp/language/array). Check Array to pointer decay. If you want it to be a "int *" - you will cast like this "return (int *)a". Also as I mentioned above - 'C++ 11' already had broken compatibility with legacy code, written in the older standards so this is not an argument. – AnArrayOfFunctions Nov 23 '14 at 18:10
  • @hvd: With this I do not disagree – Lightness Races in Orbit Nov 23 '14 at 18:15
  • 1
    @Jako: It's not an "either/or" proposition; there are _degrees_ of broken compatibility and this would be a biggie. – Lightness Races in Orbit Nov 23 '14 at 18:16
  • 1
    I don't see a "broken compatibility issue". In C and C++, arrays decay only to pointers in specific, limited contexts. If C++ specified a new return type (arrays), that would be a new context for which C had no rules. The natural not-decay behavior works as expected there. – MSalters Nov 24 '14 at 11:20
  • 2
    If it were legal to return the array, what could one do with it? It would seem odd to allow `int foo[3],bar[3]; foo=funcReturningInt3Array();` when `foo=bar;` is forbidden. If `int *moo; moo=funcReturningInt3Array();` were allowed, what would determine the lifetime of the array? – supercat Nov 02 '15 at 22:41
  • @supercat presumably, `foo =bar` would be allowed aswell and would copy the array. In your last example, I don't see anything that would warrant a different lifetime than with the today legal `moo = decltype(foo){1, 2, 3};`. – Johannes Schaub - litb Jul 28 '17 at 19:12
  • 1
    @JohannesSchaub-litb: A general ability to treat arrays as values, decaying into pointers only when they were coerced into pointers or passed as variadic arguments, would be helpful, but I don't see any practical way of adding that to the language now. – supercat Jul 28 '17 at 19:57
  • @supercat One could use the return value to initialise an array variable for starters. All the other things would need additional changed rules, for obvious reasons. But then you'd end up with std::array with an implicit conversion to T*... – rubenvb Jul 28 '17 at 22:11
0

The answer as I see it, is twofold:

  1. Compatibility with C. C doesn't work this way. Why? No idea. C never was very logical to begin with in various aspects.

  2. C++ prefers library features over language features. Seeing that C++98 was the first standard, and it mostly copied the basics from C (see point 1), this was corrected in the first major revision, C++11, which introduces the library type std::array, which, as a pure and simple library feature, solves all the abhorrent quirks that C-style arrays entail.

To summarise: even though it might make sense to have proper value semantics for arrays, it will never happen, because the apparent deficiency can be solved without making the language more complex than it already is. It is extremely difficult to get rid of legacy and backwards compatibility, so the current option of std::array is really what you want. Use it. It's simple. You'll like it. A lot.

rubenvb
  • 74,642
  • 33
  • 187
  • 332