operator << harus mengambil tepat satu argumen


94

ah

#include "logic.h"
...

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

logic.cpp

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

Ketika saya mengkompilasi, dikatakan:

std :: ostream & logic :: operator << (std :: ostream &, A &) 'harus mengambil tepat satu argumen.

Apa masalahnya?

Jawaban:


132

Masalahnya adalah Anda mendefinisikannya di dalam kelas, yaitu

a) berarti argumen kedua adalah implisit ( this) dan

b) ia tidak akan melakukan apa yang Anda inginkan, yaitu memperpanjang std::ostream.

Anda harus mendefinisikannya sebagai fungsi gratis:

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

9
Juga, dia mendeklarasikannya sebagai fungsi teman, dan mendefinisikannya sebagai fungsi anggota.
asaelr

Seperti disebutkan di en.cppreference.com/w/cpp/language/operators , "kelebihan operator >> dan operator << yang mengambil std :: istream & atau std :: ostream & sebagai argumen sebelah kiri dikenal sebagai penyisipan dan operator ekstraksi. Karena mereka mengambil tipe yang ditentukan pengguna sebagai argumen yang benar (b dalam a @ b), mereka harus diimplementasikan sebagai non-anggota ".
Morteza

49

Fungsi teman bukanlah fungsi anggota, jadi masalahnya adalah Anda menyatakan operator<<sebagai teman dari A:

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

kemudian cobalah untuk mendefinisikannya sebagai fungsi anggota kelas logic

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

Apakah Anda bingung tentang apakah logicitu kelas atau namespace?

Kesalahannya adalah karena Anda mencoba untuk mendefinisikan anggota yang operator<<mengambil dua argumen, yang berarti dibutuhkan tiga argumen termasuk thisparameter implisit . Operator hanya bisa mengambil dua argumen, sehingga saat Anda menulis a << bdua argumen tersebut adalah adan b.

Anda ingin mendefinisikan ostream& operator<<(ostream&, const A&)sebagai fungsi non- anggota , jelas bukan sebagai anggota logickarena tidak ada hubungannya dengan kelas itu!

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

3

Saya mengalami masalah ini dengan kelas template. Berikut solusi yang lebih umum yang harus saya gunakan:

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

Sekarang: * Fungsi toString () saya tidak bisa sebaris jika akan disimpan di cpp. * Anda terjebak dengan beberapa kode di header, saya tidak bisa menyingkirkannya. * Operator akan memanggil metode toString (), itu tidak sebaris.

Badan operator << dapat dideklarasikan di klausa teman atau di luar kelas. Kedua opsi itu jelek. :(

Mungkin saya salah paham atau melewatkan sesuatu, tetapi hanya menyatakan terus template operator tidak ditautkan di gcc.

Ini juga berfungsi:

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

Saya pikir Anda juga dapat menghindari masalah template yang memaksa deklarasi di header, jika Anda menggunakan kelas induk yang tidak memiliki template untuk mengimplementasikan operator <<, dan menggunakan metode toString () virtual.


0

Jika Anda mendefinisikan operator<<sebagai fungsi anggota, itu akan memiliki sintaks terdekomposisi yang berbeda dibandingkan jika Anda menggunakan non-anggota operator<<. Seorang non-anggota operator<<adalah operator biner, di mana anggota operator<<adalah operator unary.

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

Jadi .... bagaimana Anda benar-benar memanggil mereka? Operator itu aneh dalam beberapa hal, saya akan menantang Anda untuk menulis operator<<(...)sintaks di kepala Anda untuk membuat semuanya masuk akal.

MyObj mo;

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

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

Atau Anda dapat mencoba menelepon operator biner non-anggota:

MyObj mo;

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

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

Anda tidak memiliki kewajiban untuk membuat operator ini berperilaku secara intuitif saat Anda menjadikannya sebagai fungsi anggota, Anda dapat menentukan operator<<(int)shift kiri beberapa variabel anggota jika Anda mau, memahami bahwa orang mungkin sedikit lengah, tidak peduli berapa banyak komentar Anda. menulis.

Hampir terakhir, mungkin ada saat di mana kedua dekomposisi untuk panggilan operator valid, Anda mungkin mendapat masalah di sini dan kami akan menunda percakapan itu.

Terakhir, perhatikan betapa anehnya menulis operator anggota unary yang seharusnya terlihat seperti operator biner (karena Anda dapat menjadikan operator anggota virtual ..... juga berusaha untuk tidak berpindah dan menjalankan jalur ini .... )

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

    int value = 8;
};

Sintaks ini akan mengganggu banyak pembuat kode sekarang ....

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

Perhatikan bagaimana coutargumen kedua dalam rantai di sini .... ganjil kan?

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.