Casts that look like function calls?

Discussion in 'C++' started by dpbsmith.janissary.2006@gmail.com, Jan 18, 2007.

  1. Guest

    I know C++ mostly from "learning by doing." My main reference is
    Stoustrup's book. I was puzzled by something in a colleague's code that
    looked like this:

    abc=BOOL(def)

    I asked him what that was, and he said "it's a cast." I know all about
    dynamic_cast and friends, but this was something new to me. To make a
    long story short, both of my colleagues seemed to be familiar with
    writing a cast as if it were a function, although they don't normally
    write them that way, and Stoustrup's book has actual instances of this
    that appear in some of his code examples. A colleague was able to find
    something in the formal C++ syntax description indicating it's valid...
    but nobody was able to point me to any documentation, description, or
    explanation.

    If this is described in Stroustrup's book, I couldn't find it. I
    thought "deprecated C-style cast" might be it, but, no, that's just the
    regular C cast syntax, and I've verified that C compilers do _not_
    accept writing a cast as if it were a function.

    It is not a Microsoft-ism, either, which was my other thought; other
    C++ compilers seem to accept it.

    So, what the heck is it? Is it fully legitimate C++? Does it have any
    differences whatsoever from a "normal" cast, i.e. do

    hij = long(klm);
    and
    hij = (long) klm;

    compile identical code? If so, what is it there for? Is it just an
    unintended consequence of things that needed to be done to extend C
    syntax to C++? And where exactly in Stoustrup's book is it described
    and explained?
     
    , Jan 18, 2007
    #1
    1. Advertising

  2. ralpe Guest

    schrieb:

    > I know C++ mostly from "learning by doing." My main reference is
    > Stoustrup's book. I was puzzled by something in a colleague's code that
    > looked like this:
    >
    > abc=BOOL(def)


    This is normal constructor syntax. Assuming that BOOL is a type and not
    a function name the above line constructs a variable of type BOOL from
    def, which is not the same as a cast from def to BOOL. If BOOL is a
    class or struct the code will only compile if BOOL has a constructor
    that takes an argument of def's type. If BOOL is a typedef for a
    primitive type the code will compile if def is convertable to that
    type. Only in the latter case is the above line comparable to a cast.

    Ralpe
     
    ralpe, Jan 18, 2007
    #2
    1. Advertising

  3. ralpe ha escrito:

    > schrieb:
    >
    > > I know C++ mostly from "learning by doing." My main reference is
    > > Stoustrup's book. I was puzzled by something in a colleague's code that
    > > looked like this:
    > >
    > > abc=BOOL(def)


    To me, it is defined as a macro that does the simple cast and should be
    defined as:

    #define BOOL(x) (bool) x

    as you can see, everytime the BOOL(x) macro is called, the preprocessor
    will transform it onto (bool) x.

    I do not see the macro usage useful and it makes the code very hard to
    read and understand. The
     
    =?iso-8859-1?q?Ernesto_Basc=F3n?=, Jan 18, 2007
    #3
  4. Marcus Kwok Guest

    ralpe <> wrote:
    > schrieb:
    >
    >> I know C++ mostly from "learning by doing." My main reference is
    >> Stoustrup's book. I was puzzled by something in a colleague's code that
    >> looked like this:
    >>
    >> abc=BOOL(def)

    >
    > This is normal constructor syntax. Assuming that BOOL is a type and not
    > a function name the above line constructs a variable of type BOOL from
    > def, which is not the same as a cast from def to BOOL. If BOOL is a
    > class or struct the code will only compile if BOOL has a constructor
    > that takes an argument of def's type. If BOOL is a typedef for a
    > primitive type the code will compile if def is convertable to that
    > type. Only in the latter case is the above line comparable to a cast.


    Also, the function-style cast will not work for types that have a space
    in them (e.g., "unsigned long").

    --
    Marcus Kwok
    Replace 'invalid' with 'net' to reply
     
    Marcus Kwok, Jan 18, 2007
    #4
  5. On Jan 18, 3:08 pm, wrote:
    > I know C++ mostly from "learning by doing." My main reference is
    > Stoustrup's book. I was puzzled by something in a colleague's code that
    > looked like this:
    >
    > abc=BOOL(def)


    I would suspect that this is actually a macro since there is no
    BOOL-type in C++. BOOL is probably a macro looking something like this:

    #define BOOL(x) x > 0 ? 1 : 0;

    > I asked him what that was, and he said "it's a cast." I know all about
    > dynamic_cast and friends, but this was something new to me. To make a
    > long story short, both of my colleagues seemed to be familiar with
    > writing a cast as if it were a function, although they don't normally
    > write them that way, and Stoustrup's book has actual instances of this
    > that appear in some of his code examples. A colleague was able to find
    > something in the formal C++ syntax description indicating it's valid...
    > but nobody was able to point me to any documentation, description, or
    > explanation.
    >
    > If this is described in Stroustrup's book, I couldn't find it. I
    > thought "deprecated C-style cast" might be it, but, no, that's just the
    > regular C cast syntax, and I've verified that C compilers do _not_
    > accept writing a cast as if it were a function.
    >
    > It is not a Microsoft-ism, either, which was my other thought; other
    > C++ compilers seem to accept it.
    >
    > So, what the heck is it? Is it fully legitimate C++? Does it have any
    > differences whatsoever from a "normal" cast, i.e. do
    >
    > hij = long(klm);
    > and
    > hij = (long) klm;


    My compiler takes both of them without any problem. A guess would be
    that there somewhere in the standard says that there should exist
    functions with the same name as the basic types that returns a value of
    that type (so you can use it kind of like a constructor) which might be
    what the second is.

    --
    Erik Wikström
     
    =?iso-8859-1?q?Erik_Wikstr=F6m?=, Jan 18, 2007
    #5
  6. Marcus Kwok Guest

    wrote:
    [function-style casts]
    > And where exactly in Stoustrup's book is it described
    > and explained?


    I found it in Section 6.2.8 - Constructors (p.131 in the Special
    Edition).

    The T(e) construct is sometimes referred to as a function-style cast.
    Unfortunately, for a built-in type T, T(e) is equivalent to (T)e
    (section 6.2.7).

    --
    Marcus Kwok
    Replace 'invalid' with 'net' to reply
     
    Marcus Kwok, Jan 18, 2007
    #6
  7. Noah Roberts Guest

    ralpe wrote:
    > schrieb:
    >
    > > I know C++ mostly from "learning by doing." My main reference is
    > > Stoustrup's book. I was puzzled by something in a colleague's code that
    > > looked like this:
    > >
    > > abc=BOOL(def)

    >
    > This is normal constructor syntax. Assuming that BOOL is a type and not
    > a function name the above line constructs a variable of type BOOL from
    > def, which is not the same as a cast from def to BOOL.


    Not true. It is, in fact, a cast. It has exactly the same meaning as
    (BOOL)def. Many people, myself included for a long time, assume that
    such "constructor calls" are just that. For instance:

    std::string x = std::string("Hello ") + "World!";

    The call "std::string("Hello")" is a _cast_, not a constructor call or
    initialization. It resolves to the same thing as:

    std::string x = (std::string)"Hello " + "World";

    or

    std::string x = static_cast<std::string>("Hello ") + "World";

    Now all these casts eventually resolve to a constructor invocation
    because in order to cast to that type an instance of that type must be
    constructed. However, these are in fact casts and as a form of C-Style
    cast they have the same weakness (can resolve to a reinterpret without
    warning).

    Do a search in this group for discussions about "constructor calls" and
    whether or not such a thing even exists. Many argue that there is no
    way for the programmer to directly "call" the constructor. The
    standard calls all things that look like constructor calls either
    "function style cast" or "initialization".

    Even though our in our coding standard we don't allow C-style casts (I
    finally convinced everyone this was necissary) we do allow such
    function style casts in cases such as "string construction".

    <quote>
    Function style casts have the same problems as c-style casts and can be
    used in place of them. They are allowed in one case only; that is when
    they look like a constructor call:

    extern const char * str; std::string s = std::string("Hello") +
    str;

    It is often assumed that the case "std::string("Hello")" is a
    constructor call but it is actually a cast. When you could normally
    construct an object with a parameter of that type (using "new
    TYPE(x)"), a function style cast is allowed. Under no other condition
    will you use one.
    </quote>
     
    Noah Roberts, Jan 18, 2007
    #7
  8. Noah Roberts Guest

    Marcus Kwok wrote:
    > wrote:
    > [function-style casts]
    > > And where exactly in Stoustrup's book is it described
    > > and explained?

    >
    > I found it in Section 6.2.8 - Constructors (p.131 in the Special
    > Edition).
    >
    > The T(e) construct is sometimes referred to as a function-style cast.
    > Unfortunately, for a built-in type T, T(e) is equivalent to (T)e
    > (section 6.2.7).


    Stroustrup seems to deviate from the standard here then. I have to
    admit that I have never read his book.

    5.2.3 Explicit type conversion (functional notation)

    1 A simple type specifier (7.1.5) followed by a parenthesized
    expression-list constructs a value of the specified type given the
    expression list. If the expression list is a single expression, the
    type conversion expression is equivalent (in definedness, and if
    defined in meaning) to the corresponding cast expression (5.4).

    Sumarizing the rest: if it is a class type it must be complete. I the
    parameter list is more than one expression it is equivelent to creating
    and initializing a temporary rvalue of type T.
     
    Noah Roberts, Jan 18, 2007
    #8
  9. Marcus Kwok Guest

    Noah Roberts <> wrote:
    > Marcus Kwok wrote:
    >> wrote:
    >> [function-style casts]
    >> > And where exactly in Stoustrup's book is it described
    >> > and explained?

    >>
    >> I found it in Section 6.2.8 - Constructors (p.131 in the Special
    >> Edition).
    >>

    [quote moved below]
    >
    > Stroustrup seems to deviate from the standard here then. I have to
    > admit that I have never read his book.


    Hmm, maybe this can be reconciled by the part that I didn't quote.

    > 5.2.3 Explicit type conversion (functional notation)
    >
    > 1 A simple type specifier (7.1.5) followed by a parenthesized
    > expression-list constructs a value of the specified type given the
    > expression list.


    Before the other passage I quoted, he also states:

    The construction of a value of type T from a value e can be expressed
    by the functional notation T(e).

    and then gives an example of usage.

    [quote from the Standard]
    > If the expression list is a single expression, the
    > type conversion expression is equivalent (in definedness, and if
    > defined in meaning) to the corresponding cast expression (5.4).


    [original quote from Stroustrup]
    >> The T(e) construct is sometimes referred to as a function-style cast.
    >> Unfortunately, for a built-in type T, T(e) is equivalent to (T)e
    >> (section 6.2.7).


    With that addition, I don't see how it deviates from the passage from
    the Standard, though I have to admit that I haven't read the entire
    Standard in depth, nor am I an expert in Standardese.

    --
    Marcus Kwok
    Replace 'invalid' with 'net' to reply
     
    Marcus Kwok, Jan 18, 2007
    #9
  10. Ron Natalie Guest

    ralpe wrote:
    > schrieb:
    >
    >> I know C++ mostly from "learning by doing." My main reference is
    >> Stoustrup's book. I was puzzled by something in a colleague's code that
    >> looked like this:
    >>
    >> abc=BOOL(def)

    >
    > This is normal constructor syntax.


    It isn't a constructor syntax at all. It's an explicit conversion
    (function style) according to the specification. The word BOOL
    here need not be the name of a constructor. It can be any type
    name, even a typedef.

    >Only in the latter case is the above line comparable to a cast.
    >

    Completely and totally incorrect. Any time a function-style
    conversion is used with exactly one argument it is EXACTLY
    equivelent BY DEFININTION to the cast style conversion.
     
    Ron Natalie, Jan 18, 2007
    #10
  11. Ron Natalie Guest

    Marcus Kwok wrote:
    > wrote:
    > [function-style casts]
    >> And where exactly in Stoustrup's book is it described
    >> and explained?

    >
    > I found it in Section 6.2.8 - Constructors (p.131 in the Special
    > Edition).
    >
    > The T(e) construct is sometimes referred to as a function-style cast.
    > Unfortunately, for a built-in type T, T(e) is equivalent to (T)e
    > (section 6.2.7).
    >

    For any type.
     
    Ron Natalie, Jan 18, 2007
    #11
  12. Guest

    Summing up: here's what I think I've gleaned. (Oh, I forgot to explain:
    BOOL is a Microsoft-ism, but it is not a macro that takes arguments,
    it's just typedef int BOOL;)

    Suppose we have an explicit class, rather than a built-in type, like

    const int five = 5;
    class foo {
    public:
    foo(int x);
    }

    1) Then foo(five) is _not_ a "call to a constructor function;" it is,
    semantically, a _cast_ of an "int" to a "foo". However, performing the
    cast involves invoking the constructor. Sounds like Humpty-Dumpty
    language to me, but OK.

    2) Therefore, in C++, the syntax C(e), where C is a programmer-defined
    class, is a cast, not a function call.

    3) It sounds to me like an _unintended side effect,_ that occurred in
    order to avoid complicating the syntax, that T(e), where T is a
    built-in type like "long" or "float," is also a cast.

    4) It is _completely equivalent to_ (generates the same code as) C
    casting syntax.

    5) I can't quite make out what Stoustrup is saying when he says
    "Pointer conversions cannot be expressed using the T(e) notation. For
    example, char*(2) is a syntax error. Unfortunately, the protection that
    the constructor notation provides against such dangerous conversions
    can be circumvented by using typedef names." This sounds as if he first
    makes a recommendation to use the T(e) notation on the basis of safety,
    then noting that it doesn't actually provide safety.

    6) If it is not an unintended side-effect, then it seems to be
    motivated by some need for it in templates.

    7) It does not seem as if there's any particular reason to prefer this
    notation, or use it at all, except when writing templates. It would
    seem to me that anyone doing C-style casts _of pointers_ would have to
    be aware of what they are doing. It's not the case that habitually
    using these constructor-style casts would give you protection against
    mental lapses or anything like that?
     
    , Jan 19, 2007
    #12
  13. Ron Natalie Guest

    wrote:

    > 1) Then foo(five) is _not_ a "call to a constructor function;" it is,
    > semantically, a _cast_ of an "int" to a "foo". However, performing the
    > cast involves invoking the constructor.


    It's never a call to the constructor, even in the case of other than
    exactly one argument. You can't call constructors directly,
    constructors don't have return value, etc... It's a creation
    of a temporary object which involves storage allocation, and
    a few other things in addition to the invocation of the constructor.

    >
    > 2) Therefore, in C++, the syntax C(e), where C is a programmer-defined
    > class, is a cast, not a function call.


    It's never a function call when C is a type name.

    >
    > 3) It sounds to me like an _unintended side effect,_ that occurred in
    > order to avoid complicating the syntax, that T(e), where T is a
    > built-in type like "long" or "float," is also a cast.


    Huh? It's always a cast. It's never a function call.
    >
    > 4) It is _completely equivalent to_ (generates the same code as) C
    > casting syntax.


    Yes.

    >
     
    Ron Natalie, Jan 19, 2007
    #13
  14. * :
    > Summing up: here's what I think I've gleaned. (Oh, I forgot to explain:
    > BOOL is a Microsoft-ism, but it is not a macro that takes arguments,
    > it's just typedef int BOOL;)
    >
    > Suppose we have an explicit class, rather than a built-in type, like
    >
    > const int five = 5;
    > class foo {
    > public:
    > foo(int x);
    > }
    >
    > 1) Then foo(five) is _not_ a "call to a constructor function;" it is,
    > semantically, a _cast_ of an "int" to a "foo". However, performing the
    > cast involves invoking the constructor. Sounds like Humpty-Dumpty
    > language to me, but OK.


    It is /syntactically/ a cast.

    A cast is a syntax concept, what you write. A conversion is a semantic
    concept, what happens. For example

    int x;
    double y = 4.56;
    x = y; // This is a conversion, but it's not a cast.

    What happens for foo(five) depends on the type that foo is.

    While we're on the topic of terminology, I see that Ron has jumped in
    criticizing your use of "call constructor".

    The standard and most everyone else use your terminology.


    > 2) Therefore, in C++, the syntax C(e), where C is a programmer-defined
    > class, is a cast, not a function call.


    Almost right. The "therefore" is meaningless.


    > 3) It sounds to me like an _unintended side effect,_ that occurred in
    > order to avoid complicating the syntax, that T(e), where T is a
    > built-in type like "long" or "float," is also a cast.


    It's not clear why it turned out this way. But it's all bound up with
    the (1) the idea of converting constructors, and (2) the idea that
    terseness, having things done implicitly for you, is extremely valuable.
    At least one of those was perhaps not such a good idea.


    > 4) It is _completely equivalent to_ (generates the same code as) C
    > casting syntax.


    Yes.


    > 5) I can't quite make out what Stoustrup is saying when he says
    > "Pointer conversions cannot be expressed using the T(e) notation. For
    > example, char*(2) is a syntax error. Unfortunately, the protection that
    > the constructor notation provides against such dangerous conversions
    > can be circumvented by using typedef names." This sounds as if he first
    > makes a recommendation to use the T(e) notation on the basis of safety,
    > then noting that it doesn't actually provide safety.


    T(e) requires T to be a "simple type-specifier", which is a possibly
    namespace- or class- qualified class, enum, typedef or built-in type name.


    > 6) If it is not an unintended side-effect, then it seems to be
    > motivated by some need for it in templates.


    No, the basic syntax is older than templates.


    > 7) It does not seem as if there's any particular reason to prefer this
    > notation, or use it at all, except when writing templates. It would
    > seem to me that anyone doing C-style casts _of pointers_ would have to
    > be aware of what they are doing. It's not the case that habitually
    > using these constructor-style casts would give you protection against
    > mental lapses or anything like that?


    The T(e) notation does not protect you against anything.

    --
    A: Because it messes up the order in which people normally read text.
    Q: Why is it such a bad thing?
    A: Top-posting.
    Q: What is the most annoying thing on usenet and in e-mail?
     
    Alf P. Steinbach, Jan 19, 2007
    #14
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Alex
    Replies:
    0
    Views:
    407
  2. inhahe
    Replies:
    3
    Views:
    2,369
    Diez B. Roggisch
    Jan 28, 2005
  3. Patrick Kowalzick
    Replies:
    5
    Views:
    477
    Patrick Kowalzick
    Mar 14, 2006
  4. active
    Replies:
    4
    Views:
    282
    active
    Apr 3, 2007
  5. Bob
    Replies:
    5
    Views:
    262
Loading...

Share This Page