why static_cast needed here to produce proper output

Discussion in 'C++' started by nin234ATIyahoo.com, Mar 16, 2005.

  1. Hi all
    I have a logger class and facing the following issue

    enum eErrLvl
    {
    eLOG_DEBUG_5 = 1,
    eLOG_DEBUG_4,
    eLOG_DEBUG_3,
    eLOG_DEBUG_2,
    eLOG_DEBUG_1,
    eLOG_INFO,
    eLOG_WARNING,
    eLOG_ERROR,
    eLOG_FATAL
    };


    std::eek:stream&
    operator << (std::eek:stream& os, eErrLvl& eLvl)
    {
    switch (eLvl)
    {
    case eLOG_DEBUG_5:
    os << "Debug_5\t: ";
    break;
    case eLOG_DEBUG_4:
    os << "Debug_4\t: ";
    break;
    case eLOG_DEBUG_3:
    os << "Debug_3\t: ";
    break;
    case eLOG_DEBUG_2:
    os << "Debug_2\t: ";
    break;
    case eLOG_DEBUG_1:
    os << "Debug_1\t: ";
    break;
    case eLOG_INFO:
    os << "Info\t: ";
    break;
    case eLOG_WARNING:
    os << "Warn\t: ";
    break;
    case eLOG_ERROR:
    os << "Error\t: ";
    break;
    case eLOG_FATAL:
    os << "Fatal\t: ";
    break;
    }
    return os;
    }

    class srvLog
    {
    static int volatile nLglvl;

    //volatile keyword is a hint to compiler an object may change the
    value
    //in a way not specified by the language and aggressive
    optimizations
    //must be avoided

    eErrLvl nSeverity;
    public:
    friend std::eek:stream& operator << (std::eek:stream& , const
    srvLog&);

    };
    std::eek:stream& operator << (std::eek:stream& os, const srvLog& oLog)
    {
    os << "initial msg " << static_cast<eErrLvl>(oLog.nSeverity);
    return os;
    }
    My problem is with this statement
    os << "initial msg " << static_cast<eErrLvl>(oLog.nSeverity);

    Only when I use the static_cast does it invoke the operator (<<) for
    the enum. Otherwise it just prints the integer value corresponding to
    the enum
    ie if I use
    os << "initial msg " << (oLog.nSeverity);

    Ninan
     
    nin234ATIyahoo.com, Mar 16, 2005
    #1
    1. Advertising

  2. nin234ATIyahoo.com wrote:
    > [...]
    > My problem is with this statement
    > os << "initial msg " << static_cast<eErrLvl>(oLog.nSeverity);
    >
    > Only when I use the static_cast does it invoke the operator (<<) for
    > the enum. Otherwise it just prints the integer value corresponding to
    > the enum
    > ie if I use
    > os << "initial msg " << (oLog.nSeverity);


    The compiler promotes 'nSeverity' to 'int' and finds that there is
    operator << among the members of 'ostream', and uses it to output
    the value. If you static_cast it, the compiler is prevented from
    promoting the enum to int. IIRC.

    V
     
    Victor Bazarov, Mar 16, 2005
    #2
    1. Advertising

  3. actually ; that precisly is my question. Why does the compiler promote
    the enum to int, when there is already an operator defined for it
     
    nin234ATIyahoo.com, Mar 16, 2005
    #3
  4. nin234ATIyahoo.com wrote:
    > actually ; that precisly is my question. Why does the compiler promote
    > the enum to int, when there is already an operator defined for it


    Hard to say, a bug in the compiler, maybe?
     
    Victor Bazarov, Mar 16, 2005
    #4
  5. "nin234ATIyahoo.com" <> wrote in message
    news:...
    > Hi all
    > I have a logger class and facing the following issue
    >
    > enum eErrLvl
    > {
    > eLOG_DEBUG_5 = 1,
    > eLOG_DEBUG_4,
    > eLOG_DEBUG_3,
    > eLOG_DEBUG_2,
    > eLOG_DEBUG_1,
    > eLOG_INFO,
    > eLOG_WARNING,
    > eLOG_ERROR,
    > eLOG_FATAL
    > };
    >
    >
    > std::eek:stream&
    > operator << (std::eek:stream& os, eErrLvl& eLvl)
    > {


    Change the type of eLvl to either

    eErrLvl const &

    or

    eErrLvl

    of which, probably the latter is better for an enum.

    > switch (eLvl)
    > {
    > case eLOG_DEBUG_5:


    [...]

    > std::eek:stream& operator << (std::eek:stream& os, const srvLog& oLog)
    > {
    > os << "initial msg " << static_cast<eErrLvl>(oLog.nSeverity);


    oLog is const is this context, so is oLog.nSeverity. The compiler cannot
    dispatch operator<< that takes a non-const eErrLvl (as you wrote.)

    The change above should fix the problem.

    > return os;
    > }
    > My problem is with this statement
    > os << "initial msg " << static_cast<eErrLvl>(oLog.nSeverity);
    >
    > Only when I use the static_cast does it invoke the operator (<<) for
    > the enum. Otherwise it just prints the integer value corresponding to
    > the enum
    > ie if I use
    > os << "initial msg " << (oLog.nSeverity);


    Ali
     
    =?iso-8859-1?Q?Ali_=C7ehreli?=, Mar 16, 2005
    #5
  6. nin234ATIyahoo.com wrote:

    > actually ; that precisly is my question. Why does the compiler promote
    > the enum to int, when there is already an operator defined for it
    >


    You 'operator <<' for 'eErrLvl' type is declared as

    std::eek:stream& operator << (std::eek:stream& os, eErrLvl& eLvl)

    Note that it takes its second argument by non-constant reference.

    At the same time 'operator <<' for 'srvLog' takes its second operand by
    constant reference

    std::eek:stream& operator << (std::eek:stream& os, const srvLog& oLog)

    Now, inside the latter operator you are trying to do the following

    os << "initial msg " << oLog.nSeverity;

    But compiler cannot call the former operator in this case for an obvious
    reason: the "constness" of 'oLog' propagates to 'oLog.nSeverity',
    meaning that 'oLog.nSeverity' is considered to be a const-qualified
    value. Compiler cannot bind a non-constant parameter to a constant
    argument in the 'operator <<' call.

    Instead, it has to seek a workaround solution, which presents itself in
    form of a standard 'enum -> int' conversion followed by a call to
    'operator <<' for 'int's. The compiler is behaving correctly in this case.

    Strictly speaking, your 'static_cast' is not supposed to change
    anything. The result of that cast is not an lvalue and non-constant
    reference still cannot be bound to it. I don't understand why you
    compiler suddenly decides to choose your operator after the cast. _This_
    looks like a bug in the compiler.

    If you want the compiler to use your 'operator <<' for 'eErrLvl', you
    have to declare it as either

    std::eek:stream& operator << (std::eek:stream& os, eErrLvl eLvl)

    or

    std::eek:stream& operator << (std::eek:stream& os, const eErrLvl& eLvl)

    I'd stick with the first variant. There absolutely no reason to use a
    reference here, especially a non-constant one. How did you come to an
    idea to pass the 'eErrLvl' value as 'eErrLvl&' reference in the first place?

    --
    Best regards,
    Andrey Tarasevich
     
    Andrey Tarasevich, Mar 16, 2005
    #6
  7. thanks this works; I am using g++ on linux btw (gcc 3.2.3)
     
    nin234ATIyahoo.com, Mar 16, 2005
    #7
    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. Steven T. Hatton

    Would a static_cast be better style here?

    Steven T. Hatton, Apr 16, 2004, in forum: C++
    Replies:
    26
    Views:
    738
    Jerry Coffin
    Apr 19, 2004
  2. Mr. SweatyFinger
    Replies:
    2
    Views:
    2,002
    Smokey Grindel
    Dec 2, 2006
  3. Replies:
    5
    Views:
    466
    Luc The Perverse
    Oct 27, 2006
  4. Bo Peng
    Replies:
    11
    Views:
    1,094
    Victor Bazarov
    Oct 20, 2006
  5. junyangzou
    Replies:
    13
    Views:
    258
Loading...

Share This Page