Оператор << должен принимать ровно один аргумент

хиджры

#include "logic.h"
...

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

logic.cpp

#include "a.h"
...
ostream& logic::operator<<(ostream& os, A& a)
{
...
}
...

Когда я компилирую, он говорит:

станд:: ostream & логика:: operator < (std:: ostream &, A &) 'должна принимать ровно один аргумент.

В чем проблема?

Ответ 1

Проблема заключается в том, что вы определяете ее внутри класса, который

a) означает, что второй аргумент неявный (this) и

b) он не будет делать то, что вы хотите, а именно: std::ostream.

Вы должны определить его как свободную функцию:

class A { /* ... */ };
std::ostream& operator<<(std::ostream&, const A& a);

Ответ 2

Функция-друга не является функцией-членом, поэтому проблема заключается в том, что вы объявляете operator<< в качестве друга A:

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

затем попытайтесь определить его как функцию-член класса logic

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

Вы смущены тем, является ли logic классом или пространством имен?

Ошибка заключается в том, что вы пытались определить член operator<< с двумя аргументами, что означает, что он принимает три аргумента, включая неявный параметр this. Оператор может принимать только два аргумента, так что, когда вы пишете a << b, два аргумента: A и b.

Вы хотите определить ostream& operator<<(ostream&, const A&) как функцию не -member, определенно не как член logic, так как он не имеет ничего общего с этим классом!

std::ostream& operator<<(std::ostream& os, const A& a)
{
  return os << a.number;
}

Ответ 3

Я столкнулся с этой проблемой с шаблонами. Здесь более общее решение, которое я должен был использовать:

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 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;
}

Сейчас: * Функция my toString() не может быть встроенной, если она будет удалена в cpp. * Вы застряли с некоторым кодом в заголовке, я не мог избавиться от него. * Оператор вызовет метод toString(), он не вложен.

Тело оператора < может быть объявлено в статье friend или вне класса. Оба варианта уродливы.: (

Возможно, я что-то недопонимаю или что-то пропустил, но просто форвард-объявление шаблона оператора не связывается в gcc.

Это тоже работает:

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;
    }
}

Я думаю, вы также можете избежать проблем с шаблонами, вызывая объявления в заголовках, если вы используете родительский класс, который не является шаблоном для реализации оператора < < и использовать метод virtual toString().

Ответ 4

Если вы определите operator<< как функцию-член, у него будет другой разложенный синтаксис, чем если бы вы использовали не-член operator<<. Не член operator<< является бинарным оператором, где член 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;
}

Итак.... как ты их на самом деле называешь? В некотором смысле операторы странные, я призываю вас написать синтаксис operator<<(...) в вашей голове, чтобы все было понятно.

MyObj mo;

// Calling the unary operator
mo << std::cout;

// which decomposes to...
mo.operator<<(std::cout);

Или вы можете попытаться вызвать бинарный оператор, не являющийся членом:

MyObj mo;

// Calling the binary operator
std::cout << mo;

// which decomposes to...
operator<<(std::cout, mo);

Вы не обязаны заставлять эти операторы вести себя интуитивно, когда вы превращаете их в функции-члены, вы можете определить operator<<(int) для сдвига влево некоторой переменной-члена, если вы хотите, понять, что люди могут быть немного застигнуты врасплох, нет независимо от того, сколько комментариев вы можете написать.

Почти наконец, могут быть ситуации, когда обе декомпозиции для вызова оператора являются действительными, у вас могут возникнуть проблемы, и мы отложим этот разговор.

Наконец, обратите внимание, как странно было бы написать унарный оператор-член, который должен выглядеть как бинарный оператор (поскольку вы можете сделать операторы-члены виртуальными..... также пытаясь не переходить и не проходить по этому пути.... )

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

    int value = 8;
};

Этот синтаксис теперь будет раздражать многих программистов....

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");

Обратите внимание, что здесь cout является вторым аргументом в цепочке.... странно, верно?