This 'transformation' illustration only holds when one of the variables is a pointer or an array and the other is an integer type, i.e. the usual C case. In C++, a[b] loses its symmetry as operator[] can be an overloaded member function and the compiler is not allowed to use *(a+b) instead. *(a+b) might have a different type and a different value or it might not be a valid expression at all.
–
Charles BaileyMay 25 '09 at 8:15

+1. Cool. Never thought of it that way.
–
ralphtheninjaMay 25 '09 at 8:25

From the earliest days of C, the expression a[i] was simply the address of a[0] added to i (scaled up by the size of a[0]) and then de-referenced. In fact, all these were equivalent:

a[i]
i[a]
*(a+i)

====

The only thing I'd be concerned about is the actual de-referencing. Whilst they all produce the same address, de-referencing may be a concern if the types of a and i are different.

For example:

int i = 4;
long a[9];
long x = a[i]; //get the long at memory location X.
long x = i[a]; //get the int at memory location X?

I haven't actually tested that behavior but it's something you may want to watch out for. If it does change what gets de-referenced, it's likely to cause all sorts of problems with arrays of objects as well.

====

Update:

You can probably safely ignore the bit above between the ===== lines. I've tested it under Cygwin with a short and a long and it seems okay, so I guess my fears were unfounded, at least for the basic cases. I still have no idea what happens with more complicated ones because it's not something I'm ever likely to want to do.

I don't think it is different. I meant it dates from the earliest days, not that it was only like that in the early days.
–
paxdiabloMay 25 '09 at 7:44

This is wrong. Either way, the compiler knows adding an int to a long* (in either order) results in a long*, which is then dereferenced to long. And this applies for any pointer type, including user-defined.
–
Matthew FlaschenMay 25 '09 at 10:28

Wrong how. @Matthew? I've already stated that my suspicions weren't correct and that standard types worked okay. As to more complicated types, I haven't made a comment simply because it's not anything I've tried (or am likely to try).
–
paxdiabloMay 25 '09 at 10:59

Why did you post this when you voted to close? The dup had plenty of good answers, but you should have at least made this CW.
–
ZifreMay 25 '09 at 21:19

As Matthew Wilson discusses in Imperfect C++, this can be used to enforce type safety in C++, by preventing use of DIMENSION_OF()-like macros with instances of types that define the subscript operator, as in:

There's more to this, for dealing with pointers, but that requires some additional template smarts. Check out the implementation of STLSOFT_NUM_ELEMENTS() in the STLSoft libraries, and read about it all in chapter 14 of Imperfect C++.

edit: some of the commenters suggest that the implementation does not reject pointers. It does (as well as user-defined types), as illustrated by the following program. You can verify this by uncommented lines 16 and 18. (I just did this on Mac/GCC4, and it rejects both forms).

A better 'dimension' implementation can be achieved with templates: template <typename T, std::size_t N> std::size_t dimension( T[N]& x ) { return N; }. That will be safer than the sizeof(a)/sizeof(a[0]) with arrays (that have not decayed into pointers).
–
David Rodríguez - dribeasMay 25 '09 at 9:14

1

dribeas: the problem with that is that it's no longer a compile-time expression. The technique described by Wilson illustrates a compile-time version. As I said, it's available in the STLSoft libraries.
–
dcwMay 25 '09 at 9:35

There is also a way to get a compile time expression: template<typename T, std::size_t N> char (& an_array(T(&)[N]) )[N]; That will evaluate to a reference to a char array having the same size. Use it like: int v[sizeof an_array(another_array)];
–
Johannes Schaub - litbMay 25 '09 at 13:07

Note that both mine and dribea's macro are different from wilson's one, of course. Our one will reject a pointer. His one will accept it. Thus, these are different use cases.
–
Johannes Schaub - litbMay 25 '09 at 13:08

In C and C++ (with array being a pointer or array) it is a language feature: pointer arithmetic. The operation a[b] where either a or b is a pointer is converted into pointer arithmetic: *(a + b). With addition being symetrical, reordering does not change meaning.

Now, there are differences for non-pointers. In fact given a type A with overloaded operator[], then a[4] is a valid method call (will call A::operator ) but the opposite will not even compile.