conversion syntax

R

REH

It it permissible to use the constructor style cast with primitives
such as "unsigned long"? One of my compilers accepts this syntax, the
other does not. The failing one chokes on the fact that the type is
not a single identifier or keyword. Which one is correct? For example:

unsigned long x = unsigned long(y);



REH
 
J

Juha Nieminen

REH said:
It it permissible to use the constructor style cast with primitives
such as "unsigned long"? One of my compilers accepts this syntax, the
other does not. The failing one chokes on the fact that the type is
not a single identifier or keyword. Which one is correct? For example:

unsigned long x = unsigned long(y);

If I'm not mistaken, if you want to make a C-style cast to a type
which consists of several keywords, you have to enclose them in
parentheses. That is:

unsigned long x = (unsigned long)(y);

Of course the recommended way in C++ is to use a C++ style cast:

unsigned long x = static_cast<unsigned long>(y);
 
R

REH

  If I'm not mistaken, if you want to make a C-style cast to a type
which consists of several keywords, you have to enclose them in
parentheses. That is:

    unsigned long x = (unsigned long)(y);

  Of course the recommended way in C++ is to use a C++ style cast:

    unsigned long x = static_cast<unsigned long>(y);

Thanks. I know. I was just wondering if the constructor style was
legal.
 
M

Maxim Yegorushkin

  If I'm not mistaken, if you want to make a C-style cast to a type
which consists of several keywords, you have to enclose them in
parentheses. That is:

    unsigned long x = (unsigned long)(y);

  Of course the recommended way in C++ is to use a C++ style cast:

    unsigned long x = static_cast<unsigned long>(y);

The original question, IMO, involved C++ functional style cast, rather
than C-style cast.
 
J

Juha Nieminen

REH said:
Thanks. I know. I was just wondering if the constructor style was
legal.

Well, it is legal as long as your type consists of one single symbol.
For example this will always be legal:

template<typename T>
void foo()
{
T x = T(y);
}

This even if you call it like foo<unsigned long>(). That's because 'T'
is just one symbol.

Rather curiously, this is legal too:

template<typename T>
void foo()
{
T x = (T)y;
}

And this even if T is a class (with a constructor which takes a
parameter of the type of 'y').
 
P

Pascal J. Bourguignon

REH said:
It it permissible to use the constructor style cast with primitives
such as "unsigned long"? One of my compilers accepts this syntax, the
other does not. The failing one chokes on the fact that the type is
not a single identifier or keyword. Which one is correct? For example:

unsigned long x = unsigned long(y);

Well, C++ syntax is rather complex. It's understandable it's hard to
read, to understand and therefore to implement correctly. I don't
know what is specified there.

Since you observe that's a hard dark corner with diverging
implementation, my advice would be to avoid it. Or to use parentheses.

typedef unsigned long ulong;
ulong x = ulong(y);

or:

unsigned long x = (unsigned long)(y);
 
R

REH

Well, C++ syntax is rather complex.  It's understandable it's hard to
read, to understand and therefore to implement correctly.   I don't
know what is specified there.

Since you observe that's a hard dark corner with diverging
implementation, my advice would be to avoid it.  Or to use parentheses.

    typedef unsigned long ulong;
    ulong x = ulong(y);

or:

    unsigned long x = (unsigned long)(y);

Sigh. Yes, I know that. My question is simply: is the syntax legal or
not?

REH
 
P

Pascal J. Bourguignon

Maxim Yegorushkin said:
The original question, IMO, involved C++ functional style cast, rather
than C-style cast.

Which funnily, is not decided when you write:

unsigned long x = (unsigned long)(y);

The compiler could as well decide to parse it as a C cast as a C++
functional style cast. I think it'll be my favorite way to write it,
let the compiler deal with it as it wants :)
 
R

REH

Which funnily, is not decided when you write:

    unsigned long x = (unsigned long)(y);

The compiler could as well decide to parse it as a C cast as a C++
functional style cast.   I think it'll be my favorite way to write it,
let the compiler deal with it as it wants :)

Maxim understands that it was a question about syntax, not semantics.

REH
 
R

REH

It it permissible to use the constructor style cast with primitives
such as "unsigned long"? One of my compilers accepts this syntax, the
other does not. The failing one chokes on the fact that the type is
not a single identifier or keyword. Which one is correct? For example:

unsigned long x = unsigned long(y);

OK, if I read the sections in the standard defining "simple-type-
specifier" and "postfix-expression" correctly, the syntax is not
valid.

REH
 
R

REH

Which funnily, is not decided when you write:

    unsigned long x = (unsigned long)(y);

The compiler could as well decide to parse it as a C cast as a C++
functional style cast.   I think it'll be my favorite way to write it,
let the compiler deal with it as it wants :)

It don't matter how you write it, when there is a valid conversion
from T to U, these are all equivalent:

U(T);
(U) T;
static_cast<U>(T);


REH
 
R

REH

It does matter what you write. The second also applies to situations
where the others don't, and some people think that this leads to errors.

I use "doesn't matter" to mean when the three versions valid, change
from one to the other will not produce a different meaning. I agree
that c-style casts can be dangerous.

REH
 
J

James Kanze

Not a C-style cast; an "explicit type conversion (functional
notation)". The sytax for this requires either a
simple-type-specifier or a typename-specifier to the left of the
parentheses. A simple-type-specifier can be either a single
token, or a qualified type name, e.g. X::Y::Z. It cannot be the
name of a type which requires several tokens to specify, so the
answer to his question is no.

Recommended by whom? I've never seen code which didn't use the
functional notation for type conversion; if the number of
arguments is anything other than one, it's the only type of type
conversion which works. I'd strongly recommend using the new
cast syntax for pointer and reference casts, but for the others,
I generally use either a C style cast or the functional
notation.
Which funnily, is not decided when you write:
unsigned long x = (unsigned long)(y);

Yes it is. That's an "explicit type conversion (cast
notation)"---a C style cast. The functional notation has a
particularity that the others don't have: you can convert
nothing, or more than one thing:). (And yes, calling it a
conversion is a bit strange, but that's what the standard does.)
So given a user defined type A:

A() explicit type conversion (functional notation)
(A)() illegal
static_cast< A >() illegal

A( x ) explicit type conversion (functional notation)
(A)( x ) explicit type conversion (cast notation)
static_cast< A >( x ) static_cast

A( x, y ) explicit type conversion (functional notation)
(A)( x, y ) illegal
static_cast< A >( x, y ) illegal

In each group of three, all of the legal syntaxes have exactly
the same semantics (and note that A(x) doesn't necessarily call
the constructor of A---it can also call a user defined coversion
operator of x).
The compiler could as well decide to parse it as a C cast as a
C++ functional style cast. I think it'll be my favorite way
to write it, let the compiler deal with it as it wants :)

Personally, I think it would have been clearer if the cast
notation had been extended to allow multiple arguments, and the
function style casts hadn't been introduced. That would have
eliminated a lot of ambiguities. But it's too late for that
now.
 
R

REH

Not a C-style cast; an "explicit type conversion (functional
notation)".  The sytax for this requires either a
simple-type-specifier or a typename-specifier to the left of the
parentheses.  A simple-type-specifier can be either a single
token, or a qualified type name, e.g. X::Y::Z.  It cannot be the
name of a type which requires several tokens to specify, so the
answer to his question is no.

Thank you, Mr. Kanze.

REH
 
J

Juha Nieminen

James said:
Recommended by whom?

By people who think that converting between incompatible types (in
other words, reinterpret-casting) when that's not your intention is a
bad idea, and that it's better to use the casting which will make the
compiler complain.

The problem with the C-style cast is that it converts almost anything
to almost anything else, which is seldom what you want to do. Usually
you only want to cast between compatible types.
 
J

James Kanze

By people who think that converting between incompatible types
(in other words, reinterpret-casting) when that's not your
intention is a bad idea, and that it's better to use the
casting which will make the compiler complain.

Which is only relevant if there are pointers or references
involved, since all reinterpret_cast's involve pointers and
references.

As I said, I've yet to see any code in which the author avoided
things like "MyClass( x )". Which is a function style cast, and
could be rewritten "static_cast< MyClass >( x )", or things like
"MyClass()" or "MyClass( x, y )", which are function style
classes, and can't be expressed any other way.
The problem with the C-style cast is that it converts almost
anything to almost anything else, which is seldom what you
want to do. Usually you only want to cast between compatible
types.

There is, IMHO, a very definite psychological distinction.
Unless the target type is a reference, a type conversion creates
a new temporary object. In practice, however, with pointer
conversions, we normally think in terms of the pointed to object
(i.e. almost as if it were a reference), and there are several
different conversions possible. So we want a syntax to 1) state
explicitly which conversion we want, and 2) be highly visible
and easy to find, because we are going to access an object in an
unusual way. When converting between numeric types, on the
other hand (e.g. an int to an unsigned long), neither of these
issues are relevant, and we (or I, at least) think of it more
along the same lines as we do things like MyClass( x ). In
other words, a function style cast. Except that if we cannot
name the target type with a single word, we have to add
parentheses around it, which turns it into a C style cast.

In practice, I'll never use a C style cast or a functional style
cast for a pointer or a reference, and I'll almost never use
anything but a functional style cast when explicitly creating a
temporary object of class type (converting to a class type); for
numeric types, I tend to use functional or C style casts, but
I'll occasionally use a static_cast too.
 
J

James Kanze

[...]
The problem with the C-style cast is that it converts almost
anything to almost anything else, which is seldom what you
want to do. Usually you only want to cast between compatible
types.
And sadly, C++-style functional casts have this same danger.

Except that the danger is only really present if the target type
is a pointer or a reference, and functional casts can't be used
in such cases.
 
H

Hendrik Schober

James said:
[...]
The problem with the C-style cast is that it converts almost
anything to almost anything else, which is seldom what you
want to do. Usually you only want to cast between compatible
types.
And sadly, C++-style functional casts have this same danger.

Except that the danger is only really present if the target type
is a pointer or a reference, and functional casts can't be used
in such cases.

I consider this
enum colors { red, green, blue };
colors c = colors(10);
dangerous.

Schobi
 
J

James Kanze

James said:
[...]
The problem with the C-style cast is that it converts
almost anything to almost anything else, which is seldom
what you want to do. Usually you only want to cast between
compatible types.
And sadly, C++-style functional casts have this same danger.
Except that the danger is only really present if the target
type is a pointer or a reference, and functional casts can't
be used in such cases.

I consider this
enum colors { red, green, blue };
colors c = colors(10);
dangerous.

In the same sense that
int i = int( 3.14159 ) ;
is dangerous, yes. In the case of user defined types, you could
do some runtime checking, but only if you overloaded enough to
avoid the implicit conversions. Because in the end, if you have
MyClass, with a constructor which takes an int, what is the
different between:
int i = int( 3.14159 ) ;
and
MyClass c( 3.14159 ) ;

There is, IMHO, a real problem in that many such dangerous
conversions are not only allowed, but happen implicitly. IIRC,
Stroustrup wanted to change this at one point, but the committee
wouldn't follow him. So we're more or less stuck with them.

FWIW: in the case of your first example, with enum's, I probably
would use a static_cast. And it do sometimes use a static_cast
for narrowing conversions, although I'm not systematic about it.
On the other hand, I see no reason to not use a functional style
cast, or a C style cast, to convert an int to double, in order
to force floating point, or a C style cast to convert an int to
unsigned long, in order to force the arithmetic to be in
unsigned long (which is the example we're talking about).
 
H

Hendrik Schober

James said:
James said:
[...]
The problem with the C-style cast is that it converts
almost anything to almost anything else, which is seldom
what you want to do. Usually you only want to cast between
compatible types.
And sadly, C++-style functional casts have this same danger.
Except that the danger is only really present if the target
type is a pointer or a reference, and functional casts can't
be used in such cases.
I consider this
enum colors { red, green, blue };
colors c = colors(10);
dangerous.

In the same sense that
int i = int( 3.14159 ) ;
is dangerous, yes. [...]

No, IMO the enum example is more dangerous.
For starters, enums are commonly switched over. The conversion
from pi to 'int' is well-defined, the result is a valid 'int'.
The conversion from '10' to 'color', OTOH, is neither defined
nor is the result valid.
[...] Because in the end, if you have
MyClass, with a constructor which takes an int, what is the
different between:
int i = int( 3.14159 ) ;
and
MyClass c( 3.14159 ) ;

That, in the case of 'MyClass', you can implement the ctor so
that it deals with this?
There is, IMHO, a real problem in that many such dangerous
conversions are not only allowed, but happen implicitly. IIRC,
Stroustrup wanted to change this at one point, but the committee
wouldn't follow him. So we're more or less stuck with them.

I agree.
FWIW: in the case of your first example, with enum's, I probably
would use a static_cast. And it do sometimes use a static_cast
for narrowing conversions, although I'm not systematic about it.
On the other hand, I see no reason to not use a functional style
cast, or a C style cast, to convert an int to double, in order
to force floating point, or a C style cast to convert an int to
unsigned long, in order to force the arithmetic to be in
unsigned long (which is the example we're talking about).

(I read this as if you are more or less agreeing with me that
the function-style cast from 'int' to some enum is probably
more dangerous than between number types.)

Schobi
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,169
Messages
2,570,919
Members
47,459
Latest member
Vida00R129

Latest Threads

Top