George2 said:
The following code,
Code:
operator const Outer::Inner * volatile & ();
1.
I think it means an operator &, which returns const Inner*
type and takes no arguments, right?
That would be:
const Outer::Inner * volatile operator & ();
The above is an implicit conversion operator, converting the
class in which it is defined to a Outer::Inter const* volatile&.
A top level volatile on a return value is ignored unless the
type is a class type. Here 1) the type isn't a class type, but
a reference, and 2) the volatile isn't top level, i.e. it isn't
on the return type. What the volatile means here is that you
limit enormously what the user can do with the pointer referred
to. (As Alf pointed out, this is probably a case of exploiting
the type system---what's important here isn't the semantics of
volatile, but the fact that T* volatile isn't the same type as
T* volatile.)
What a silly, incomplete, and absolutely wrong statement!
It's incomplete, but that's all. Formally, except for a few
special cases (e.g. with longjmp/setjmp), the semantics of
volatile are implementation defined. Practically, however, most
implementations define them as inhibiting some optimizations.
extern volatile unsigned int vui; // defined and initialized elsewhere
unsigned int silly_func()
{
return vui * 2;
}
Are you really claiming that the compiler is forbidden from
making the strength reduction optimization of replacing the
multiply with a left shift by 1?
No, but if the compiler inlines this function, and happens to
find that it has vui in a register, as a result of a previous
calculation, it will still reread it. (Or more correctly, it
will still generate a machine instruction to load it from
memory. On most modern hardware, this does not necessarily mean
that it will actually reread it from global memory. In sum, the
implementation defined semantics of volatile are, in most cases,
totally useless for anything.)