Bug 52114 - SFINAE out the rvalue iostream operators to give better error messages
Summary: SFINAE out the rvalue iostream operators to give better error messages
Status: NEW
Alias: None
Product: gcc
Classification: Unclassified
Component: libstdc++ (show other bugs)
Version: 4.7.0
: P3 enhancement
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2012-02-03 18:53 UTC by Ben Longbons
Modified: 2012-02-05 11:11 UTC (History)
2 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2012-02-04 00:00:00


Attachments
Use SFINAE in delayed return type to make sure there's an lvalue version (405 bytes, patch)
2012-02-03 18:53 UTC, Ben Longbons
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Ben Longbons 2012-02-03 18:53:00 UTC
Created attachment 26566 [details]
Use SFINAE in delayed return type to make sure there's an lvalue version

Currently, if there is no stream insertion/extraction operator defined for a class, it tries to use the template that takes an rvalue istream or ostream and anything on the right.

Actual Result:
error: cannot bind ‘std::ostream {aka std::basic_ostream<char>}’ lvalue to ‘std::basic_ostream<char>&&’
/usr/include/c++/4.6/ostream:581:5: error:   initializing argument 1 of ‘std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&&, const _Tp&) [with _CharT = char, _Traits = std::char_traits<char>, _Tp = Foo]’

Expected Result:
error: no match for ‘operator<<’ in ‘std::cout << Foo()’
note: candidates are:

Note that this patch is not safe to apply to 4.6 because of bug 51878
Comment 1 Jonathan Wakely 2012-02-04 19:01:47 UTC
seems like a good idea
Comment 2 Paolo Carlini 2012-02-04 20:32:31 UTC
Indeed and easy to do.

Yesterday I was wondering: is there something in C++11 saying explicitly that these tricks are allowed, or some sort of blanket statement explaining how the  return type specifications are meant to be read? Adding Daniel in CC.
Comment 3 Paolo Carlini 2012-02-04 20:39:58 UTC
(PS: Daniel tweaked tuple_cat the same way)
Comment 4 Daniel Krügler 2012-02-04 21:44:24 UTC
(In reply to comment #3)
> (PS: Daniel tweaked tuple_cat the same way)

There is a difference here: For tuple_cat we have a user constraint that says that the template argument shall be a tuple_cat, but encourage the library to support other types satisfying the tuple-like protocol. Further, tuple_cat is a named function and hard to reach unintentionally. I tend to say that the approach here is what a good library should do. But it might be a good idea to open a library issue to require a reduced set of overload resolution participation for any conforming implementation for the new two generic inserter and extractor.
Comment 5 Ben Longbons 2012-02-04 22:36:54 UTC
(In reply to comment #2)
> Yesterday I was wondering: is there something in C++11 saying explicitly that
> these tricks are allowed,
In N3242, 14.8.2/{7,8}
Comment 6 Paolo Carlini 2012-02-04 22:49:17 UTC
Thanks Daniel.

Ben, I know SFINAE ;) what I was looking for is something *in the library* chapters saying somehow explicitly that for overload resolution purposes or other QoI purposes late return types are fine (vs the letter of the specs in terms of return types)
Comment 7 Jonathan Wakely 2012-02-04 22:53:11 UTC
(In reply to comment #5)
> (In reply to comment #2)
> > Yesterday I was wondering: is there something in C++11 saying explicitly that
> > these tricks are allowed,
> In N3242, 14.8.2/{7,8}

The question is not about the language rules, we know it works. The question is whether modifying the signature of the function is allowed. It would change the return type if called for a type that overloads operator<< with a return type that is not ostream&
Comment 8 Jonathan Wakely 2012-02-04 22:54:51 UTC
But using decltype((o<<t), std::ostream&) would solve that.
Comment 9 Paolo Carlini 2012-02-04 22:58:06 UTC
Jon, interesting
Comment 10 Paolo Carlini 2012-02-04 22:59:54 UTC
I mean, your idea seems a nice operative answer to my vague nervousness ;)
Comment 11 Daniel Krügler 2012-02-05 11:00:00 UTC
(In reply to comment #8)
> But using decltype((o<<t), std::ostream&) would solve that.

I agree that this would be much better but I suggest to cast the first expression to void to prevent overloaded operator, to be in effect here. I still think that a library issue should be opened for this.
Comment 12 Paolo Carlini 2012-02-05 11:11:34 UTC
I agree it should, thanks Daniel. In fact, I see that implementing the trick in a fully correct way is less than trivial and, AFAIK, there is no hint at all in the Standard that something similar is in order.