3

I'm trying to overload the >> operator in a class inside a namespace, but as soon as I try to use it with a string stream it doesn't work. Here's a distilled version of my code:

#include <iostream>
#include <string>
#include <sstream>

using namespace std;

namespace Foo {
    class Bar {
    public:
        string str;
        friend istream& operator >>(istream& in, Bar& t);
    };
}

inline istream& operator >>(istream& in, Foo::Bar& t) {
    in >> t.str;
    return in;
}

int main() {
    Foo::Bar foo;
    stringstream("foo") >> foo;

    cout << foo.str << endl;

    return 0;
}

and here's the error:

main.cpp:22:22: error: no match for ‘operator>>’ (operand types are ‘std::stringstream {aka std::__cxx11::basic_stringstream<char>}’ and ‘Foo::Bar’)

The thing is these other ways of doing it work:

#include <iostream>
#include <string>
#include <sstream>

using namespace std;

namespace Foo {
    class Bar {
    public:
        string str;
        friend istream& operator >>(istream& in, Foo::Bar& t) {
            in >> t.str;
            return in;
        }
    };
}



int main() {
    Foo::Bar foo;
    stringstream("foo") >> foo;

    cout << foo.str << endl;

    return 0;
}
#include <iostream>
#include <string>
#include <sstream>

using namespace std;

class Bar {
public:
    string str;
    friend istream& operator >>(istream& in, Bar& t);
};

inline istream& operator >>(istream& in, Bar& t) {
    in >> t.str;
    return in;
}

int main() {
    Bar foo;
    stringstream("foo") >> foo;

    cout << foo.str << endl;

    return 0;
}

The thing is, I have no idea why the first way of doing it should be wrong. I'm using the g++ compiler on linux if that helps. Could someone help me understand what's going on?

7
  • 3
    Trick question: when you declare a function inside a namespace, what namespace is that function a part of? What namespace is your >> operator a part of? Thinks carefully, and you should be able to figure out the answer yourself. Commented Jul 17, 2019 at 2:11
  • stringstream("foo") is an rvalue, which can't be bound to the first parameter of (either of) your operator(s). That's masking the useful error message Commented Jul 17, 2019 at 2:17
  • I'm actually quite perplexed as to why the latter examples are compiling... Commented Jul 17, 2019 at 2:20
  • They compile because they define the overloaded operator in the same namespace where it's declared. Unlike the first example. Should've tried to answer my trick question... Commented Jul 17, 2019 at 2:21
  • @SamVarshavchik Sure, they are defined in the same namespace in the latter examples, but why would stringstream("foo") still bind to the istream& parameter? Commented Jul 17, 2019 at 2:23

1 Answer 1

2

Thanks to hints from Sam Varshavchik (in the comments above), I've been able to come up with a correct version of the first version:

#include <iostream>
#include <string>
#include <sstream>

namespace Foo {
    class Bar {
    public:
        std::string str;
        friend std::istream& operator >>(std::istream& in, Bar& t);
    };

    std::istream& operator >>(std::istream& in, Bar& t);
}

std::istream& Foo::operator >>(std::istream& in, Foo::Bar& t) {
    in >> t.str;
    return in;
}

using namespace std;

int main() {
    Foo::Bar foo;
    stringstream("foo") >> foo;

    cout << foo.str << endl;

    return 0;
}

The key was making sure that the operator>> function was both declared and defined in the same scope. I still wanted to be able to define the function outside of the namespace braces, so I had to add a declaration inside the namespace so the compiler would know that there's supposed to be that function in the namespace. Keeping the function definition separate allowed me to separate my code into three files, main.cpp, foo.hpp, and foo.cpp:

// main.cpp

#include <iostream>
#include <string>
#include <sstream>

#include "foo.hpp"

using namespace std;

int main() {
    Foo::Bar foo;
    stringstream("foo") >> foo;

    cout << foo.str << endl;

    return 0;
}
// foo.hpp

#ifndef FOO_HPP
#define FOO_HPP

#include <string>
#include <iostream>

namespace Foo {
    class Bar {
    public:
        std::string str;
        friend std::istream& operator >>(std::istream& in, Bar& t);
    };

    std::istream& operator >>(std::istream& in, Bar& t);
}

#endif
// foo.cpp

#include "foo.hpp"

std::istream& Foo::operator >>(std::istream& in, Foo::Bar& t) {
    in >> t.str;
    return in;
}

Anyways, thanks so much for the help! And thanks for not hand-feeding me a solution; it's so much better to learn by figuring it out myself, even if I did get some help pointing me in the right direction.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.