Reputation: 70472
When attempting to use an rvalue reference, I get an error from GCC (clang does not generate an error).
Why is the compiler generating an error? Is it a bug in GCC?
The "simplified" error is:
|In file included from /usr/include/c++/8/sstream:38,
| from .code.tio.cpp:1:
|/usr/include/c++/8/istream: In instantiation of 'struct std::__is_extractable<std::istream&, std::istream& (*&)(std::istream&, std::string&), void>':
|/usr/include/c++/8/type_traits:131:12: required from 'struct std::__and_<std::__is_convertible_to_basic_istream<std::istringstream > >, std::__is_extractable<std::istream&, std::istream& (*&)(std::istream&, std::string&), void> >'
|/usr/include/c++/8/type_traits:136:12: required from 'struct std::__and_<std::__not_<std::is_lvalue_reference<std::istringstream > > >, std::__is_convertible_to_basic_istream<std::istringstream > >, std::__is_extractable<std::istream&, std::istream& (*&)(std::istream&, std::string&), void> >'
|/usr/include/c++/8/istream:980:5: required by substitution of 'template<class _Istream, class _Tp> typename std::enable_if<std::__and_<std::__not_<std::is_lvalue_reference<_Tp> >, std::__is_convertible_to_basic_istream<_Istream>, std::__is_extractable<typename std::__is_convertible_to_basic_istream<_Tp>::__istream_type, _Tp&&, void> >::value, typename std::__is_convertible_to_basic_istream<_Tp>::__istream_type>::type std::operator>>(_Istream&&, _Tp&&) [with _Istream = std::istringstream; _Tp = std::istream& (*&)(std::istream&, std::string&)]'
|.code.tio.cpp:12:32: required from here
|/usr/include/c++/8/istream:951:12: error: no match for 'operator>>' (operand types are 'std::istream' and 'std::istream& (*)(std::istream&, std::string&)')
| __void_t<decltype(declval<_Istream&>()
| ~~~~~~~~~~~~~~~~~~~~
| >> declval<_Tp>())>>
| ^~~~~~~~~~~~~~~~~
The code I am trying to compile is:
typedef std::istream &getline_type(std::istream &, std::string &);
void operator>>(std::istream &, getline_type) {} // 1
void operator>>(std::istream &&, getline_type) {}
int main()
{
std::string s;
getline_type *getline = std::getline; // 2
//using std::getline; // 3
std::istringstream("a") >> getline;
}
If I comment out the line marked // 1
, it works. If I use the line marked // 3
instead of // 2
, it also works.
I believe clang is correctly assessing that the code is well-formed, but if there is a valid reason to reject the code, it might indicate a bug in clang.
Upvotes: 3
Views: 143
Reputation: 40013
This does appear to be a GCC bug: the line at which the overload resolution fails is part of the declaration of a partial specialization for a trait, so a substitution failure should just have the usual effect of eliminating the “overload” (the partial specialization) and thus producing false_type
for the trait. Then the operator>>
template specialization would itself be eliminated for the same reason, leaving your overloads. I assume that GCC is letting your functions bleed into the lookup set (but only partially, since it then rejects for want of an istream&
overload after all).
Upvotes: 1