Overloading istream_iterator -— cannot bind lvalue to ‘std::basic_istream&&’

后端 未结 1 683
轻奢々
轻奢々 2021-01-22 13:54

I\'ve done some reseach like:

  • Overloading operator<<: cannot bind lvalue to ‘std::basic_ostream&&’
  • Overloading operator<<: cannot bind
相关标签:
1条回答
  • 2021-01-22 14:26

    To understand what's the problem, we have to take a look at an exemplary implementation of istream_iterator (the problem arises from the requirements of the Standard, which are implicitly shown here):

    template < class T, class CharT, class Traits, class Distance >
    class istream_iterator
    {
        /* ... */
        typedef std::basic_istream<CharT, Traits>  istream_type;
        istream_type* stored_istream_ptr;
        T value;
    
    public:
        /* ... */
        istream_iterator& operator++()
        {
            *stored_istream_ptr >> value; // (A)
            return *this;
        }
        T const& operator*() const
        {
            return value;
        }
        /* ... */
    };
    

    In line (A), an operator is applied to objects of dependent types:

    • value is of type T
    • stored_istream_ptr is of type istream_type, see the typedef

    According to [temp.dep.type]/8, both types are dependent.

    For the expression A >> B as well as for any other function call, first the name of the function is looked up (here: operator>>) -> name lookup, then, from the set of found functions (overloads), the most viable is chosen and called -> overload resolution.

    For an operator, both member and non-member functions (such as your operators) are looked up.

    In this case, the involved types are dependent, therefore special rules for name lookup apply [temp.dep.res]/1:

    In resolving dependent names, names from the following sources are considered:

    • Declarations that are visible at the point of definition of the template.
    • Declarations from namespaces associated with the types of the function arguments both from the instantiation context (14.6.4.1) and from the definition context.

    Your operators have been defined in the global namespace, which is not associated to neither std::basic_istream nor std::pair. Therefore, name resolution does not find your operators and overload resolution for the expression in line (A) fails.


    This would explain clang 3.2's error message:

    stream_iterator.h:120:17: error: invalid operands to binary expression ('istream_type' (aka 'basic_istream < char, std::char_traits >') and 'std::pair')

           *_M_stream >> _M_value;
           ~~~~~~~~~~ ^  ~~~~~~~~
    

    And it explains why the workarounds work.

    g++ on the other hand seems to only show one overload found by name resolution and the reason it's rejecting it (whereas clang++ shows all overloads found by name resolution with a reason for every single one why it has been rejected). The one g++ shows might be the "best fitting":

    template< class CharT, class Traits, class T >
    basic_istream<CharT,Traits>& operator>>(basic_istream<CharT,Traits>&&, T&);
    

    Which is, AFAIK, just a wrapper to call the other operator>> in the case the expression istream_obj >> value operates on a rvalue (like get_istream() >> value).

    This is unrelated to your problem (and confusing).


    Two workarounds:

    • use a wrapper type to wrap std::pair such that you can define the operator>> in a namespace associated with that wrapper type
    • inject your operators in namespace std (not recommended??)
    0 讨论(0)
提交回复
热议问题