operator << must take exactly one argument

前端 未结 4 2055
一个人的身影
一个人的身影 2020-12-04 12:06

a.h

#include \"logic.h\"
...

class A
{
friend ostream& operator<<(ostream&, A&);
...
};

logic.cpp

#inclu         


        
相关标签:
4条回答
  • 2020-12-04 12:22

    If you define operator<< as a member function it will have a different decomposed syntax than if you used a non-member operator<<. A non-member operator<< is a binary operator, where a member operator<< is a unary operator.

    // Declarations
    struct MyObj;
    std::ostream& operator<<(std::ostream& os, const MyObj& myObj);
    
    struct MyObj
    {
        // This is a member unary-operator, hence one argument
        MyObj& operator<<(std::ostream& os) { os << *this; return *this; }
    
        int value = 8;
    };
    
    // This is a non-member binary-operator, 2 arguments
    std::ostream& operator<<(std::ostream& os, const MyObj& myObj)
    {
        return os << myObj.value;
    }
    

    So.... how do you really call them? Operators are odd in some ways, I'll challenge you to write the operator<<(...) syntax in your head to make things make sense.

    MyObj mo;
    
    // Calling the unary operator
    mo << std::cout;
    
    // which decomposes to...
    mo.operator<<(std::cout);
    

    Or you could attempt to call the non-member binary operator:

    MyObj mo;
    
    // Calling the binary operator
    std::cout << mo;
    
    // which decomposes to...
    operator<<(std::cout, mo);
    

    You have no obligation to make these operators behave intuitively when you make them into member functions, you could define operator<<(int) to left shift some member variable if you wanted to, understand that people may be a bit caught off guard, no matter how many comments you may write.

    Almost lastly, there may be times where both decompositions for an operator call are valid, you may get into trouble here and we'll defer that conversation.

    Lastly, note how odd it might be to write a unary member operator that is supposed to look like a binary operator (as you can make member operators virtual..... also attempting to not devolve and run down this path....)

    struct MyObj
    {
        // Note that we now return the ostream
        std::ostream& operator<<(std::ostream& os) { os << *this; return os; }
    
        int value = 8;
    };
    

    This syntax will irritate many coders now....

    MyObj mo;
    
    mo << std::cout << "Words words words";
    
    // this decomposes to...
    mo.operator<<(std::cout) << "Words words words";
    
    // ... or even further ...
    operator<<(mo.operator<<(std::cout), "Words words words");
    

    Note how the cout is the second argument in the chain here.... odd right?

    0 讨论(0)
  • 2020-12-04 12:24

    I ran into this problem with templated classes. Here's a more general solution I had to use:

    template class <T>
    class myClass
    {
        int myField;
    
        // Helper function accessing my fields
        void toString(std::ostream&) const;
    
        // Friend means operator<< can use private variables
        // It needs to be declared as a template, but T is taken
        template <class U>
        friend std::ostream& operator<<(std::ostream&, const myClass<U> &);
    }
    
    // Operator is a non-member and global, so it's not myClass<U>::operator<<()
    // Because of how C++ implements templates the function must be
    // fully declared in the header for the linker to resolve it :(
    template <class U>
    std::ostream& operator<<(std::ostream& os, const myClass<U> & obj)
    {
      obj.toString(os);
      return os;
    }
    

    Now: * My toString() function can't be inline if it is going to be tucked away in cpp. * You're stuck with some code in the header, I couldn't get rid of it. * The operator will call the toString() method, it's not inlined.

    The body of operator<< can be declared in the friend clause or outside the class. Both options are ugly. :(

    Maybe I'm misunderstanding or missing something, but just forward-declaring the operator template doesn't link in gcc.

    This works too:

    template class <T>
    class myClass
    {
        int myField;
    
        // Helper function accessing my fields
        void toString(std::ostream&) const;
    
        // For some reason this requires using T, and not U as above
        friend std::ostream& operator<<(std::ostream&, const myClass<T> &)
        {
            obj.toString(os);
            return os;
        }
    }
    

    I think you can also avoid the templating issues forcing declarations in headers, if you use a parent class that is not templated to implement operator<<, and use a virtual toString() method.

    0 讨论(0)
  • 2020-12-04 12:27

    A friend function is not a member function, so the problem is that you declare operator<< as a friend of A:

     friend ostream& operator<<(ostream&, A&);
    

    then try to define it as a member function of the class logic

     ostream& logic::operator<<(ostream& os, A& a)
              ^^^^^^^
    

    Are you confused about whether logic is a class or a namespace?

    The error is because you've tried to define a member operator<< taking two arguments, which means it takes three arguments including the implicit this parameter. The operator can only take two arguments, so that when you write a << b the two arguments are a and b.

    You want to define ostream& operator<<(ostream&, const A&) as a non-member function, definitely not as a member of logic since it has nothing to do with that class!

    std::ostream& operator<<(std::ostream& os, const A& a)
    {
      return os << a.number;
    }
    
    0 讨论(0)
  • 2020-12-04 12:31

    The problem is that you define it inside the class, which

    a) means the second argument is implicit (this) and

    b) it will not do what you want it do, namely extend std::ostream.

    You have to define it as a free function:

    class A { /* ... */ };
    std::ostream& operator<<(std::ostream&, const A& a);
    
    0 讨论(0)
提交回复
热议问题