0

I have the friends in a class definition obviously and to make it clearer, have removed the implementation code etc...

class Ref { public: Ref(char* s, size_t l) : _s(s), _l(l) {} private: char* _s; size_t _l; }; class foo { public: friend stringstream& operator>>(std::stringstream& s, uint8_t& v) { return s; } friend stringstream& operator>>(std::stringstream& s, const Ref& r) { return s; } private: std::stringstream ss; void example(void) { char b[256]; Ref r(b, sizeof(b)); uint8_t i; ss >> i >> r; <------ Why do I get an error here? ss >> r >> i; <------ But this one seems to compile fine. } }; 
8
  • 3
    You say your friends are in the class definition but in your code they are not. Which one is right, your statement or the code? Commented Sep 30, 2013 at 14:03
  • 2
    When asking about an error, always include the full error message. Commented Sep 30, 2013 at 14:04
  • After changing l(_l) to _l(l), removing the friend keywords (since they can't appear outside a class definition) and changing char* b[256] to char b[256] and sticking the relevant code in a main(), this compiled just fine for me. Commented Sep 30, 2013 at 14:07
  • 1
    @GuyGreer Are you sure? The results of ss >> i should be of type std::istream, and there's no >> for istream >> Ref. Commented Sep 30, 2013 at 14:09
  • @JamesKanze He had overloaded (in the global namespace) operator>> for uint8_t and std::stringstream to return a std::stringstream & and the compiler found that one before the one in namespace std in <sstream>. After his edit, however, now this does not compile because this same overload is now in class foo the overload is never considered and the expected one in <sstream> is found through ADL. Commented Sep 30, 2013 at 14:17

2 Answers 2

5

Why are you overloading on std::stringstream? You should always be overloading on std::istream or std::ostream (depending on the direction). It's exceedingly rare that std::stringstream would even be used (std::istringstream or std::ostringstream would usually be more appropriate), and even if they were, operator>> will normally return a std::istream&, not a std::stringstream&.

EDIT:

With regards to why one seemed to work:

ss >> r >> i; 

is

operator>>( operator>>( ss, r ), i ); 

You have defined an operator>> which takes a stringstream& and Ref const&, so the inner call is valid. And your operator>> returns a stringstream&, which isA std::istream, so the function operator>>( std::istream&, unsigned char ) can be called. Where as:

ss >> i >> r; 

is

operator>>( operator>>( ss, i ), r ); 

The inner call returns an std::istream&, and there is no overloaded operator>> for std::istream&, Ref const&.

As stated above: overloaded >> should always take std::istream& as there first argument, and return an std::istream&.

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

7 Comments

perhaps you could comment on why his overload friend stringstream& operator>>(std::stringstream& s, uint8_t& v) doesn't get called.
@GuyGreer Maybe because it isn't visible. If he defined it in a class, then it can only be found with ADL, and ADL will only look in the namespace(s) the operator is in and in std:: for something like uint8_t. (But of course, my fundamental answer stands: you overload on std::istream&, and not on std::stringstream---a class I've never used.)
@GuyGreer And looking at his complete code: he's invoking the >> operator in a context where all of his >> will be found, so he'll get an ambiguous overload for ss >> i.
Agreed about the std::istream& and your answer, this was more for completeness, since the OP probably expected this overload to be found and used as well.
@GuyGreer That's the fun thing about ADL: sometimes you find it, sometimes you don't. Depending on the context where he tried his two statements, one or the other would fail, for different reasons.
|
1
ss >> i >> r; <------- why do I get an error here? 

You forgot to tell us what the error is, or to post the actual code that gives you the error. When I fix the obvious errors in the posted code, I get:

cannot bind ‘std::basic_istream<char>’ lvalue to ‘std::basic_istream<char>&&’ 

The first problem is that ss >> i won't call your overload; you can't overload the streaming operators for built-in types like uint8_t. So this will call the overload defined by the standard library, which returns a reference to istream, not stringstream. Your operator expects a reference to stringstream, so the second operator will fail.

You should follow the convention and work with a generic ostream rather than a specific stringstream:

friend std::istream& operator>>(std::istream& s, const Ref& r) { return s; } 

If you actually want the operator to do anything useful, then you'll need to remove the const from the second argument.

1 Comment

It's okay, the const is intentional because it's a temporary object and only it's internal methods are used by the operator and nothing is modified.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.