Keith Thompson:
<quibble>
It decays when used in a context other than as the operand of a unary
"&" or "sizeof" operator, (That's probably what you meant by "value
context".)
</quibble>
I'll give my own understanding of it (which is sound for both C and C++).
First thing:
A conversion won't occur unless it needs to occur.
For intance, in the following, there's no need for a conversion, as an int
can be assigned directly to an int:
int a=0,b;
b = a;
Here's an example however of a place where a conversion need take place:
int a=0; double b;
b = a;
The thing to remember is that if there's no need for a conversion, there
won't be a conversion.
Here's an example of where there's no need for a conversion:
int arr[15];
sizeof arr;
The array type won't implicitly convert to a pointer to its first element,
and that's because sizeof can work with any type, thus relieving the need
for a conversion to a pointer to the first element. So once again, a
conversion doesn't take place unless it needs to take place.
Here though, is an example of where a conversion need take place:
int *p = arr;
Just as how a double can implicitly convert to an int, an array can
implicitly convert to a pointer to its first element.
One thing to note though, is that none of the following operators work on
arrays:
+ (addition)
- (subtraction)
* (dereference)
[] (subscript)
All of these operators work with pointers rather than arrays. Therefore, if
you try to use them on an array, then you necessitate an implicit
conversion to a pointer to the first element.
My own understanding of "conversion won't take place unless it has to"
works well for me, because it satisfies my needs both as a C programmer and
as a C++ programmer.
In C, I believe you can count on one hand the places where an array can
actually stay as an array, so such a verbose explanation as this isn't
necessary. However, in C++, it's more complicated on account of references,
function overloading, templates, etc..
<OFF-TOPIC>
I realise this is horribly off-topic, but just to satisfy anyone's
curiosity, here's an example of where this understanding would work well in
C++. Here are two overloads of the same function:
void Func(int *p) {}
void Func(int (&arr)[10]) {}
The first overload takes a pointer, while the second takes a reference to
an array of 10 int's. If we were to invoke "Func" in code such as the
following:
int main()
{
int arr[10];
Func(arr);
}
, then we know which overload will be invoked because we know that a
conversion will only take place when it needs to take place. In this
particular case, there's no need for the implicit conversion to a pointer
to the first element, as the array object itself can be used.
</OFF-TOPIC>