Thread: Confused about operator overloading warning message

  1. #1
    Registered User Sharke's Avatar
    Join Date
    Jun 2008
    Location
    NYC
    Posts
    303

    Confused about operator overloading warning message

    I know its a mistake to declare the second parameter here as a const, but I don't understand the error message:

    Code:
    istream& operator>>(istream& is, const X& x)
    {
        is >> x.ch;
        return is;
    }
    
    warning C4717: 'operator>>' : recursive on all control paths, function will cause runtime stack overflow

  2. #2
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    Presumably the function call >> x.ch either calls this function again, or is defined in terms of this function, etc.

  3. #3
    Registered User Sharke's Avatar
    Join Date
    Jun 2008
    Location
    NYC
    Posts
    303
    Quote Originally Posted by tabstop View Post
    Presumably the function call >> x.ch either calls this function again, or is defined in terms of this function, etc.
    I still don't understand, because the only reason for the warning message is the const. If I remove it, there's no warning.

  4. #4
    Registered User Sharke's Avatar
    Join Date
    Jun 2008
    Location
    NYC
    Posts
    303
    OK. It looks like I posted this in the C# forum instead of the C++ forum

    It's off to the opticians for me.

  5. #5
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Moved to C++ Programming forum.

    Quote Originally Posted by Sharke
    I still don't understand, because the only reason for the warning message is the const. If I remove it, there's no warning.
    The const is logically wrong, but I am not sure what to make of the warning either. I suggest that you post the smallest and simplest program that demonstrates the warning message.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  6. #6
    Registered User Sharke's Avatar
    Join Date
    Jun 2008
    Location
    NYC
    Posts
    303
    OK this should do it:

    Code:
    #include <iostream>
    using namespace std;
    
    class X
    {
        char ch;
    public:
        X(char chch): ch(chch) {}
        friend ostream& operator<<(ostream& os, const X& x)
        {
            return os << x.ch;
        }
        friend istream& operator>>(istream& is, const X& x);
    };
    
    
    istream& operator>>(istream& is, const X& x)
        {
            return is >> x.ch;
        }
    
    int main() {}
    I'm only given the warning message (VC++ Express) if the operator>> friend function is defined outside of the class body and if the second parameter is declared as const. If I take the const out, no warning message. However, if I define the function inside the body of the class like I have with operator<<, I'm given no warning even with the const. Warnings are set at level 4.

  7. #7
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Oh, I think I know why: there is an implicit conversion from char to X, thus the expression is >> x.ch causes a temporary X to be constructed, and then this temporary is then used as an argument to operator>>, hence causing infinite recursion.

    If you had declared the constructor as explicit, then problem would have surfaced in a different way. In fact, the MinGW port of g++ 3.4.5 does not warn that infinite recursion can happen with the -Wall option.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  8. #8
    Registered User Sharke's Avatar
    Join Date
    Jun 2008
    Location
    NYC
    Posts
    303
    Quote Originally Posted by laserlight View Post
    Oh, I think I know why: there is an implicit conversion from char to X, thus the expression is >> x.ch causes a temporary X to be constructed..
    Why the conversion from char to X? And why the different behavior when the function is defined outside of the class body?

  9. #9
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by Sharke
    Why the conversion from char to X?
    Because you have a constructor that takes a char. Consider:
    Code:
    class X
    {
        char ch;
    public:
        X(char chch): ch(chch) {}
    };
    
    void foo(const X& x)
    {
    }
    
    int main()
    {
        foo('a');
    }
    Quote Originally Posted by Sharke
    And why the different behavior when the function is defined outside of the class body?
    Maybe MSVC's static analysis only detected the infinite recursion when the non-member function was defined outside of the class definition.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  10. #10
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    >> Why the conversion from char to X?

    X is const and so X.ch is as well. Since there isn't a corresponding istream::operator >> for const char& (obviously) the compiler chooses the next best thing, ie: to invoke the constructor of temporary of type X.

    >> And why the different behavior when the function is defined outside of the class body?

    Compiler peculiarity.
    Last edited by Sebastiani; 06-14-2009 at 10:35 AM. Reason: smileys disabled
    Code:
    #include <cmath>
    #include <complex>
    bool euler_flip(bool value)
    {
        return std::pow
        (
            std::complex<float>(std::exp(1.0)), 
            std::complex<float>(0, 1) 
            * std::complex<float>(std::atan(1.0)
            *(1 << (value + 2)))
        ).real() < 0;
    }

  11. #11
    Registered User Sharke's Avatar
    Join Date
    Jun 2008
    Location
    NYC
    Posts
    303
    I think I see! Thanks guys. That's another small piece of icing on my C++ cake. If I stop the constructor from taking a char (or make it explicit) then no conversion takes place and I get an appropriate error message about >> not taking a right hand operand of const char.
    Last edited by Sharke; 06-14-2009 at 11:07 AM.

  12. #12
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    >> If I stop the constructor from taking a char then no conversion takes place and I get an appropriate error message about >> not taking a right hand operand of const char.

    Another option is to disallow implicit conversion by declaring the constructor like so:

    Code:
    explicit X(char chch): ch(chch) {}
    Code:
    #include <cmath>
    #include <complex>
    bool euler_flip(bool value)
    {
        return std::pow
        (
            std::complex<float>(std::exp(1.0)), 
            std::complex<float>(0, 1) 
            * std::complex<float>(std::atan(1.0)
            *(1 << (value + 2)))
        ).real() < 0;
    }

  13. #13
    Registered User Sharke's Avatar
    Join Date
    Jun 2008
    Location
    NYC
    Posts
    303
    Quote Originally Posted by Sebastiani View Post
    >> If I stop the constructor from taking a char then no conversion takes place and I get an appropriate error message about >> not taking a right hand operand of const char.

    Another option is to disallow implicit conversion by declaring the constructor like so:

    Code:
    explicit X(char chch): ch(chch) {}
    Beat you to it by one minute in the edit!

    At least I finally understand what explicit is for....I'd kind of skimmed over the explanation in my book because my mind wasn't in the right place.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. File Server Help
    By lautarox in forum C Programming
    Replies: 146
    Last Post: 09-24-2008, 06:32 PM
  2. C Warning message
    By PaulStat in forum C Programming
    Replies: 11
    Last Post: 11-28-2006, 06:22 AM
  3. Replies: 28
    Last Post: 07-16-2006, 11:35 PM
  4. Dev-cpp - compiler options
    By tretton in forum C Programming
    Replies: 7
    Last Post: 01-06-2006, 06:20 PM
  5. Help me find this error and get rid of this warning message please
    By caduardo21 in forum Windows Programming
    Replies: 4
    Last Post: 02-18-2005, 09:21 PM