Struktur data STL mana dengan tipe penyimpanan tidak lengkap yang dapat digunakan sebagai anggota kelas?

Sejauh yang saya tahu, sejak C++17 beberapa struktur data STL mungkin "ada" dengan tipe yang tidak lengkap sebagai parameter templat yang menggambarkan tipe yang disimpan. Misalnya, saya dapat menggunakan std::unique_ptr<Incomplete> (saya tidak yakin apakah itu struktur data) atau std::vector<Incomplete> sebagai anggota kelas jika semua properti kelas (yang memerlukan definisi Incomplete) diimplementasikan dalam file .cpp terpisah:

class Incomplete;
using Complete = int;
class Foo {
private:
  std::unique_ptr<Incomplete> u_p;
  std::vector<Incomplete> v;
  std::deque<Incomplete> d;
  std::list<Incomplete> l;
  std::set<Incomplete> s;
  std::unordered_map<Complete, Complete> u_m_cc;
  std::unordered_map<Complete, Incomplete> u_m_ci;
  std::unordered_map<Incomplete, Complete> u_m_ic;
  std::unordered_map<Incomplete, Incomplete> u_m_ii;
public:
  // implemented in a separate .cpp which has Incomplete defined:
  Foo();
  Foo(Foo&&);
  Foo& operator=(Foo&&);
  Foo(Foo const&);
  Foo& operator=(Foo const&);
  ~Foo();
};

Jadi, manakah dari anggota data yang tercantum di atas yang valid untuk penggunaan tersebut? Bagaimana dengan struktur data lainnya, smart pointer, dll.?


person passing_through    schedule 01.02.2020    source sumber
comment
Apakah itu dikompilasi atau tidak? Jika tidak, anggota mana yang menghasilkan pesan diagnostik?   -  person eerorika    schedule 01.02.2020
comment
@eerorika std::vector dan std::unique_ptr baik-baik saja, std::unordered_map menolak bekerja di MSVC saya: std::pair menggunakan struct yang tidak lengkap. Bahkan jika ia mengkompilasi sesuatu, itu tidak dijamin sesuai standar, itulah masalah yang saya lihat dalam pengujian tersebut.   -  person passing_through    schedule 01.02.2020
comment
Kontainer STL yang dialokasikan pada heap akan bekerja dengan tipe yang tidak lengkap. Yang dialokasikan di tumpukan tidak akan dan akan memerlukan header yang sesuai. std::pair adalah POD, jadi container apa pun dengan std::pair sebagai anggotanya tidak akan berfungsi dengan tipe yang tidak lengkap. Satu pengecualian menarik untuk ini adalah union di mana alokasi ada di tumpukan tetapi hanya anggota pertama dari daftar gabungan yang harus bertipe lengkap. Yang lain mungkin tidak lengkap. Jika saya ingat, std::optional mengeksploitasi properti ini.   -  person cplusplusrat    schedule 01.02.2020
comment
@cplusplusrat apakah ini dinyatakan dalam standar C++17 (atau sebelumnya)? Apakah ini berarti saya tidak dapat menggunakan std::unordered_map dengan tipe penyimpanan yang tidak lengkap? Jika ya, apakah ada alternatif lain?   -  person passing_through    schedule 01.02.2020
comment
@walnut: Bagaimana tipe sepele (secara otomatis) dapat memiliki sumber daya heap?   -  person Davis Herring    schedule 02.02.2020
comment
@DavisHerring yang saya maksud adalah std::pair itu sendiri, bukan anggotanya. Seperti tipe lainnya, std::pair itu sendiri dapat berada di stack atau heap. Saya menyebutkan hal itu karena beberapa kalimat pertama dalam komentar yang saya balas membuatnya terdengar seolah-olah std::pair bersikap sepele menghalangi std::unordered_map menerima tipe yang tidak lengkap, yang sejauh yang saya tahu tidak demikian.   -  person walnut    schedule 02.02.2020
comment
Jika ada yang tertarik: untuk melanjutkan hanya dengan deklarasi maju, gunakan boost container dengan alokasi heap (dan pengalokasi yang sesuai, tentu saja; yang default adalah OK): itu diperbolehkan secara eksplisit.   -  person passing_through    schedule 03.02.2020


Jawaban (2)


Dengan asumsi tidak ada anggota kelas yang digunakan secara eksplisit atau implisit hingga tipenya selesai:

Argumen templat selalu tidak lengkap untuk std::unique_ptr dan std::shared_ptr sejak C++11, lihat [unique.ptr]/5 dan [util.smartptr.shared]/2 masing-masing.

Dukungan untuk tipe yang tidak lengkap dalam container telah ditambahkan dengan N4510 hingga C++17, tetapi hanya untuk

std::vector
std::list
std::forward_list

dan hanya jika pengalokasi yang digunakan memenuhi persyaratan kelengkapan pengalokasi, yaitu, meskipun tipe nilai itu sendiri tidak lengkap, tipe pengalokasi X itu sendiri adalah tipe yang lengkap dan begitu pula semua anggota std::allocator_traits<X>, kecuali ::value_type. Pengalokasi default std::allocator memenuhi persyaratan ini.

Tak satu pun dari wadah lain dapat digunakan dengan tipe yang tidak lengkap. Menurut proposal yang ditautkan di atas, cakupannya terbatas pada tiga wadah ini "sebagai langkah pertama" karena implementasi besar sudah mendapat dukungan untuk hal tersebut.

person walnut    schedule 01.02.2020

sejak C++17 beberapa struktur data STL mungkin "ada" dengan tipe yang tidak lengkap sebagai parameter templat yang menjelaskan tipe yang disimpan.

Ini tidak benar.

Sejak C++17, beberapa tipe STL mungkin dideklarasikan dengan tipe yang tidak lengkap sebagai parameter templat.

Pada saat tipe diinisiasi, tipe tersebut harus sudah lengkap.

Misalnya: (kode yang belum diuji)

struct T; // incomplete
using TV = std::vector<T>; // declared a type using incomplete type T; fine.

TV tv0; // attempt to declare a variable of type TV; fails to compile.

struct T { int v; }; // T is now complete
TV tv1; // compiles
person Marshall Clow    schedule 01.02.2020
comment
Terima kasih atas koreksinya. Saya masih tidak mengerti penggunaan mana yang saya jelaskan yang valid, jika ada. Bisakah Anda membantu bagian ini? - person passing_through; 01.02.2020
comment
Dalam contoh OP tidak ada anggota container yang dipakai sampai tipenya selesai. Membuat instance std::vector itu sendiri (tetapi bukan anggotanya) dengan tipe yang tidak lengkap secara eksplisit diperbolehkan di C++17. Saya tidak mengerti bagaimana penjelasan Anda menjawab pertanyaan itu. - person walnut; 01.02.2020
comment
Tipe list, forward_list dan vector dipanggil secara eksplisit di C++17 - person Marshall Clow; 01.02.2020