Re: Variables in for loop (style issue)
Walter Bright wrote:
[...]
Let me clarify the two cases here:
1) This is legal, standard conforming code:
void foo(const int& end)
{ int* p = &const_cast<int&>(end);
*p = 3; // modify x
}
int x;
foo(x);
2) This is undefined behavior:
void foo(const int& end)
{ int* p = &const_cast<int&>(end);
*p = 3; // modify const x
}
const int x;
foo(x);
The only difference is whether x is const or not, not whether foo()
takes a reference to const. So we are back to const as type modifier
having no useful meaning to an optimizer.
Const as storage class, however, is treated very differently, i.e. it
can actually assumed to be constant (and so can be used in "constant
propagation" compiler optimizations).
The "const" in "const int x;" is a type qualifier, not a storage class.
If it were a storage class, the type of &x would be "int*", yet it is
"int const*". Even grammatically it is not a storage class. And
it can have a use for an optimizer whether it's part of the specifiers
or the declarator:
int const x; // Top-level const.
int *const p; // Top-level const too.
In my statements about the (lack of) utility of const, I am talking
about type modifier const, not storage class const. D does have storage
class const.
Back to the loop example, given:
void foo(const int& end)
{ int* p = &const_cast<int&>(end);
*p = 3; // modify const x
}
const int end = ...;
for (int i = 0; i < end; i++)
{
foo(end);
}
Yes, I agree with you here that the addition of const (as storage class)
to 'end' means that the optimizer can assume that 'end' is loop
invariant, even though foo() attempts to modify it. And yes, my
optimizer will treat top level storage class const as being constant,
regardless of whether a pointer or reference to it is taken or not.
Where the optimizer ignores const is when const is used as a type
modifier. For the loop case, the fact that foo takes a reference to
const is of no value to the optimizer. The only thing of value is if
'end' itself is storage class const or not.
I think we've been misunderstanding each other, and I hope this clears
it up.
Probably. I only meant to correct your original (accidental?) claim
regarding the fact that the "const" in your "const int end = ..." is
not useful.
> >>> It's technically only one meaning (with two grammatical
locations,
although both location can be useful for optimization purposes):
A type qualifier. From an optimization perspective, it's only useful
when appearing at the top level of a variable type. (That's probably
what you mean by the "storage class meaning", but the language
is consistent in treating is as a type qualifier.)
The Standard does treat the two cases differently, for example, see
7.1.5.1-2:
"A variable of const qualified integral or enumeration type initialized
by an integral
constant expression can be used in integral constant expressions (5.19)."
It treats various cases of constness in special ways, but its always
in terms of the type system. You mention one special case,
It's not just a special case, it is a crucial distinction from which
follows that const as a storage class means that the data can actually
be assumed to be constant by the compiler. Any other use of const cannot
assume this. While I agree that the standard refers to the storage class
const in terms of the type system, it's behavior is that of a storage
class, not a type. The two behaviors are fundamentally different, and
are at the root of the special cases listed in the standard.
I disagree: See my notes above. If it's behavior was not that of
typing,
the type of entity "x" and its derived entities would not have "const"
in it.
In C++, the type system applies to entities and to expressions.
An entity is immutable (except for its "mutable" parts) if its type is
const.
An entity of type "ref to const" is not const. A entity of type
"pointer to
const" is not const. Even a const member function is not const in that
sense.
Expressions are different: They're just access paths to object or
function
entities. Hence, an expression by itself cannot determine whether an
entity is mutable or not based of the constness of types involved
(because
there isn't a 1-to-1 mapping of paths to entities).
All this is quite consistent in the C++ type system.
Where I might agree with you, is that it might not be worth the trouble
and
instead a language could be better off not modelling constness in the
type system (by moving immutability to a storage class).
Daveed
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]