Pertanyaan C++ STL terkait dengan penyisipan iterator dan operator kelebihan beban

#include <list>
#include <set>
#include <iterator>
#include <algorithm>

using namespace std;

class MyContainer {
public:
 string value;

    MyContainer& operator=(const string& s) {
        this->value = s;
        return *this;
    }
};

int main() 
{
    list<string> strings;
    strings.push_back("0");
    strings.push_back("1");
    strings.push_back("2");

    set<MyContainer> containers;
    copy(strings.begin(), strings.end(), inserter(containers, containers.end()));
}

Kode sebelumnya tidak dapat dikompilasi. Dalam mode C++ standar, keluaran kesalahannya bertele-tele dan sulit dimengerti. Bagian kuncinya tampaknya adalah ini...

/usr/include/c++/4.4/bits/stl_algobase.h:313: error: no match for ‘operator=’ in ‘__result.std::insert_iterator::operator* [with _Container = std::set, std::allocator >]() = __first.std::_List_iterator::operator* [with _Tp = std::basic_string, std::allocator >]()’

...yang saya tafsirkan berarti bahwa operator penugasan yang dibutuhkan tidak ditentukan. Saya melihat kode sumber untuk insert_iterator dan mencatat bahwa itu telah membebani operator penugasan. Algoritme penyalinan harus menggunakan operator penugasan iterator yang kelebihan beban untuk melakukan tugasnya (?).

Saya kira karena iterator masukan saya ada pada wadah string dan iterator keluaran saya ada pada wadah MyContainers sehingga operator penugasan insert_iterator yang kelebihan beban tidak dapat lagi berfungsi.

Ini tebakan terbaik saya, tapi mungkin saya salah.

Jadi, mengapa hal ini tidak berhasil dan bagaimana saya dapat mencapai apa yang saya coba lakukan?


person rshepherd    schedule 21.04.2010    source sumber


Jawaban (3)


Apa yang akan berhasil jika menggunakan konstruktor (yang akan lebih masuk akal daripada penugasan):

class MyContainer {
public:
 string value;

    MyContainer(const string& s): value(s) {
    }
};

Lalu permasalahan yang kedua adalah himpunan juga mengharuskan isinya dapat diperbandingkan.

Mengenai penyebabnya, insert_iterator bekerja dengan membebani operator= secara berlebihan:

insert_iterator<Container>& operator= (typename Container::const_reference value);

Seperti yang Anda lihat, nilai di sebelah kanan harus berupa tipe nilai dari container atau dapat dikonversi secara implisit ke dalamnya, yang merupakan hal yang dicapai oleh konstruktor (non-eksplisit) dan tidak dicapai oleh operator penugasan.


Secara teknis Anda juga dapat membuatnya berfungsi tanpa mengubah kelas (misalnya jika Anda tidak menginginkan konstruktor non-eksplisit) dengan menyediakan fungsi konversi yang sesuai:

MyContainer from_string(const std::string& s)
{
    MyContainer m;
    m = s;    //or any other method how to turn a string into MyContainer
    return m;
}

yang dapat digunakan dengan std::transform:

transform(strings.begin(), strings.end(), inserter(containers, containers.end()), from_string);
person UncleBens    schedule 21.04.2010
comment
std::set membutuhkan operator<() - person wilhelmtell; 22.04.2010
comment
Sebenarnya tidak. Ini adalah masalah sampingan di sini, dan disebutkan secara singkat dalam jawabannya. - person UncleBens; 22.04.2010

Anda perlu menambahkan:
1. Konstruktor yang menggunakan string (Anda mencoba menambahkan string ke wadah yang dapat berisi objek MyContainer).
2. operator bool ‹ (set menggunakannya secara default untuk membandingkan elemen)
Misalnya:

class MyContainer
{
  public:
   MyContainer(const string& v):value(v){};
};
bool operator <(const MyContainer &c1, const MyContainer &c2)
{
return c1.value <c2.value;
}
person a1ex07    schedule 21.04.2010

Masalahnya ada dua:

  1. Anda mencoba mengisi sekumpulan MyContainer objek
  2. ... dari daftar string objek.

Algoritma copy() mencoba mengubah setiap objek string menjadi objek MyContainer. Di C++ untuk menambahkan dukungan konversi kelas MyContainer dari tipe string ke tipe MyContainer Anda perlu menambahkan konstruktor yang mengambil parameter tipe string:

struct MyContainer {
    MyContainer(const string& s) : value(s) { }
    bool operator<(const MyContainer& o) const { return value < o.value; }

private:
    string s;
};

Anda tidak memerlukan operator penugasan, karena kompiler dapat menyelesaikan penyalinan oleh konstruktor salinan: ubah string menjadi MyContainer lalu gunakan operator penugasan default untuk menugaskan satu objek MyContainer ke objek lainnya. Namun Anda memerlukan operator<() karena set C++ diurutkan.

person wilhelmtell    schedule 21.04.2010