Why are arrays of references illegal?
The following code does not compile.
int a = 1, b = 2, c = 3;
int& arr[] = {a,b,c,8};
What does the C++ standard say about this?
I know I could declare a class that contains a reference, then create an array of that class, as shown below. But I really want to know why the code above doesn't compile.
struct cintref
{
cintref(const int & ref) : ref(ref) {}
operator const int &() { return ref; }
private:
const int & ref;
void operator=(const cintref &);
};
int main()
{
int a=1,b=2,c=3;
//typedef const int & cintref;
cintref arr[] = {a,b,c,8};
}
It is possible to use struct cintref
instead of const int &
to simulate an array of references.
Answering to your question about standard I can cite the C++ Standard §8.3.2/4:
There shall be no references to references, no arrays of references, and no pointers to references.
That's because references are not objects and doesn't occupy the memory so doesn't have the address. You can think of them as the aliases to the objects. Declaring an array of nothing has not much sense.
References are not objects. They don't have storage of their own, they just reference existing objects. For this reason it doesn't make sense to have arrays of references.
If you want a light-weight object that references another object then you can use a pointer. You will only be able to use a struct
with a reference member as objects in arrays if you provide explicit initialization for all the reference members for all struct
instances. References cannot be default initalized.
Edit: As jia3ep notes, in the standard section on declarations there is an explicit prohibition on arrays of references.
This is an interesting discussion. Clearly arrays of refs are outright illegal, but IMHO the reason why is not so simple as saying 'they are not objects' or 'they have no size'. I'd point out that arrays themselves are not full-fledged objects in C/C++ - if you object to that, try instantiating some stl template classes using an array as a 'class' template parameter, and see what happens. You can't return them, assign them, pass them as parameters. ( an array param is treated as a pointer). But it is legal to make arrays of arrays. References do have a size that the compiler can and must calculate - you can't sizeof() a reference, but you can make a struct containing nothing but references. It will have a size sufficient to contain all the pointers which implement the references. You can't instantiate such a struct without initializing all the members:
struct mys {
int & a;
int & b;
int & c;
};
...
int ivar1, ivar2, arr[200];
mys my_refs = { ivar1, ivar2, arr[12] };
my_refs.a += 3 ; // add 3 to ivar1
In fact you can add this line to the struct definition
struct mys {
...
int & operator[]( int i ) { return i==0?a : i==1? b : c; }
};
...and now I have something which looks a LOT like an array of refs:
int ivar1, ivar2, arr[200];
mys my_refs = { ivar1, ivar2, arr[12] };
my_refs[1] = my_refs[2] ; // copy arr[12] to ivar2
&my_refs[0]; // gives &my_refs.a == &ivar1
Now, this is not a real array, it's an operator overload; it won't do things that arrays normally do like sizeof(arr)/sizeof(arr[0]), for instance. But it does exactly what I want an array of references to do, with perfectly legal C++. Except (a) it's a pain to set up for more than 3 or 4 elements, and (b) it's doing a calculation using a bunch of ?: which could be done using indexing (not with normal C-pointer-calculation-semantics indexing, but indexing nonetheless). I'd like to see a very limited 'array of reference' type which can actually do this. I.e. an array of references would not be treated as a general array of things which are references, but rather it would be a new 'array-of-reference' thing which effectively maps to an internally generated class similar to the one above (but which you unfortunately can't make with templates).
this would probably work, if you don't mind this kind of nasty: recast '*this' as an array of int *'s and return a reference made from one: (not recommended, but it shows how the proper 'array' would work):
int & operator[]( int i ) { return *(reinterpret_cast<int**>(this)[i]); }
Comment to your edit:
Better solution is std::reference_wrapper
.
Details: http://www.cplusplus.com/reference/functional/reference_wrapper/
Example:
#include <iostream>
#include <functional>
using namespace std;
int main() {
int a=1,b=2,c=3,d=4;
using intlink = std::reference_wrapper<int>;
intlink arr[] = {a,b,c,d};
return 0;
}
An array is implicitly convertable to a pointer, and pointer-to-reference is illegal in C++