|
Boost : |
From: danl_miller (danl_miller_at_[hidden])
Date: 2002-02-19 20:42:54
--- In boost_at_y..., "mfdylan" <dylan_at_m...> wrote:
> --- In boost_at_y..., "danl_miller" <danl_miller_at_b...> wrote:
> > as: "The storage classes in C++ are static, auto, register, and
> > volatile except that auto is weird in that it also is combinable
> with
> > other storage classes (i.e. the true storage classes) to have
> > non-storage-class behavior."
>
> volatile is not a storage class, it's a cv-qualifier like const.
> And in fact in C you could also omit the storage class and specify
> just the cv-qualifier:
>
> main()
> {
> volatile i = 0;
> const j = 0;
> }
>
> If we allowed this for the proposed implicit typing scheme then
given:
>
> void foo(std::string s)
> {
> const t = s.c_str();
> ...
> }
>
> Would the type of t be const char* or const char* const? (I would
> have thought the latter).
Good point. My gaff stimulated something productive. I amend my
previous attempt to redirect the auto proposal away from merely auto.
Instead of considering the type-implied-by-initialization language
feature to be triggered by the presence of auto, let's consider the
type-implied-by-initialization language feature to be triggered by the
presence of a storage-class and/or cv-qualifier without the rest of
the type. Reworking my prior troublesome examples:
Consider:
> void fooNonconstNonconst()
> {
> int i = 11;
> int j = 3;
> auto hmmm1 = i+j; // const? or noncost?
> ++hmmm1; // legal? or illegal?
> }
which would become:
void fooNonconstNonconst()
{
int i = 11;
int j = 3;
const hmmm1_a = i+j; // definitely constant
auto hmmm1_b = i+j; // nonconst variable by lack of const
auto const hmmm1_c = i+j; // definitely constant
++hmmm1_b; // definitely legal
}
Likewise consider:
> void fooConstConst()
> {
> const int x = 12;
> const int y = 4;
> auto hmmm2 = x+y; // const? or noncost?
> ++hmmm2; // legal? or illegal?
> }
which would become:
void fooConstConst()
{
const int x = 12;
const int y = 4;
const hmmm2_a = x+y; // definitely constant
auto hmmm2_b = x+y; // nonconst variable by lack of const
auto const hmmm2_c = x+y; // definitely constant
++hmmm2_b; // definitely legal
}
Likewise consider:
> void fooConstNonconst()
> {
> const int p = 13;
> int q = 5;
> auto hmmm3 = p+q; // const? or noncost?
> ++hmmm3; // legal? or illegal?
> }
which would become:
void fooConstNonconst()
{
const int p = 13;
int q = 5;
const hmmm3_a = p+q; // definitely constant
auto hmmm3_b = p+q; // nonconst variable by lack of const
auto const hmmm3_c = p+q; // definitely constant
++hmmm3_b; // definitely legal
}
As we can see, all of the troublesome cases which my prior email
mentioned are cured with the adjustment where the type-deduction does
not transfer the rvalue's storage-class to the lvalue nor transfer the
rvalue's cv-qualifier to the lvalue. The proposed
type-implied-by-initialization language feature would be limited to:
A) transferring the simple-type-specifier from rvalue to lvalue
B) not transferring the storage class from rvalue to lvalue:
mutable, register, auto, static, extern
C) transferring only the cv-qualifiers of the types pointed to by
pointers or referenced by references (not transferring the
cv-qualifier present or implied by the pointer or reference address).
For example:
C1) transferring the const on the following because it is not the
pointer's address which is constant but rather the characters in the
array are constant
void foo()
{
const char* c = "CONSTANT";
volatile v = c; // c is type auto const char*
// but v is of type auto const char* volatile
// where the const is required, otherwise
// the constant string literal "CONSTANT"
// would be modifiable if v were to be
// incorrectly implied to be of type
// auto char* volatile
}
C2) not transferring the const on the following because it is the
reference's address which is constant but rather the integer's value
is permitted to change
void bar( int parm_ )
{
int& r = parm_;
auto p = &r; // &r is a constant address/pointer
// but p is implied to be of type int*
// where the constantness of the reference's
// address (a natural property of references)
// does not cause p to be constant. If one
// wanted p's address to be constant, then
// the expressivity is there as shown by pc:
auto const pc = &r;
}
Enhancing content from my prior email, the concept of a declaration
becomes one of the following (in simplified colloquial grammar):
1) storage-class type identifier and so forth
e.g., the existing
static int foo;
and
auto float bar;
2) storage-class cv-qualifier type identifier and so forth
e.g., the existing
extern const float pi;
and
static volatile int* asicRegister;
3) type identifier and so forth
e.g., the existing
int foo;
and
float bar;
4) storage-class identifier and so forth
e.g., the proposed
auto fooNonconst = "example";
for a nonconst pointer to constant char array but also
static barNonconst = 3.1415F
for a variable float
5) storage-class cv-qualifier identifier and so forth
e.g., the proposed
auto volatile fooVolatile = "initial string";
for a volatile pointer to constant char array but also
static const barConst = 3.1415F
for a constant float
(BTW, my now-fortuitous gaff was that I knew there were historically
4 storage classes---oops, now 5 nowadays including mutable. In my
tight time-period that I had to get all of those thoughts out, my
brain glommed onto volatile as the 4th storage class instead of
extern.)
> Also it's not clear whether specifying the storage class after the
cv-
> qualifier is allowed (Comeau online gives a warning).
>
> extern is the other storage class, which can only be used to
> initialise a variable outside of block scope.
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk