Di era pencerahan tahun 2016, dengan dua standar baru di bawah ikat pinggang kami sejak pertanyaan ini diajukan dan yang baru sudah dekat, hal penting untuk diketahui adalah bahwa kompiler yang mendukung standar C ++ 17 akan mengkompilasi kode Anda apa adanya .
Pengurangan argumen template untuk template kelas di C ++ 17
Di sini (hasil edit oleh Olzhas Zhumabek dari jawaban yang diterima) adalah makalah yang merinci perubahan yang relevan dengan standar.
Mengatasi masalah dari jawaban lain
Jawaban peringkat teratas saat ini
Jawaban ini menunjukkan bahwa "copy konstruktor dan operator=
" tidak akan mengetahui spesialisasi template yang benar.
Ini tidak masuk akal, karena konstruktor salinan standar dan operator=
hanya ada untuk jenis template yang dikenal :
template <typename T>
class MyClass {
MyClass(const MyClass&) =default;
... etc...
};
// usage example modified from the answer
MyClass m(string("blah blah blah"));
MyClass *pm; // WHAT IS THIS?
*pm = m;
Di sini, seperti yang saya catat di komentar, tidak ada alasan untuk MyClass *pm
menjadi deklarasi hukum dengan atau tanpa bentuk inferensi baru: MyClass
bukan tipe (ini template), jadi tidak masuk akal untuk mendeklarasikan pointer dari tipe MyClass
. Berikut salah satu cara yang mungkin untuk memperbaiki contoh:
MyClass m(string("blah blah blah"));
decltype(m) *pm; // uses type inference!
*pm = m;
Berikut, pm
adalah sudah dari jenis yang tepat, dan kesimpulan yang sepele. Selain itu, tidak mungkin untuk mencampur tipe secara tidak sengaja saat memanggil konstruktor salinan:
MyClass m(string("blah blah blah"));
auto pm = &(MyClass(m));
Di sini, pm
akan menjadi penunjuk ke salinan m
. Di sini, MyClass
sedang dikonstruksi dari m
—yang bertipe MyClass<string>
(dan bukan tipe yang tidak ada MyClass
). Dengan demikian, pada titik di mana pm
tipe 's disimpulkan, ada adalah informasi yang cukup untuk mengetahui bahwa template-jenis m
, dan karena itu template-jenis pm
, yangstring
.
Selain itu, berikut ini akan selalu memunculkan kesalahan kompilasi :
MyClass s(string("blah blah blah"));
MyClass i(3);
i = s;
Ini karena deklarasi konstruktor salinan tidak memiliki template:
MyClass(const MyClass&);
Di sini, tipe template argumen copy-constructor cocok dengan tipe template kelas secara keseluruhan; yaitu, saat MyClass<string>
dibuat instance, MyClass<string>::MyClass(const MyClass<string>&);
dibuat instance-nya, dan ketika MyClass<int>
dibuat, MyClass<int>::MyClass(const MyClass<int>&);
dibuat instance-nya. Kecuali ditentukan secara eksplisit atau konstruktor templatized dideklarasikan, tidak ada alasan bagi compiler untuk membuat instanceMyClass<int>::MyClass(const MyClass<string>&);
, yang jelas tidak sesuai.
Jawabannya oleh Cătălin Pitiș
Pitiș memberikan contoh deduksi Variable<int>
dan Variable<double>
, kemudian menyatakan:
Saya memiliki nama jenis yang sama (Variabel) dalam kode untuk dua jenis yang berbeda (Variabel dan Variabel). Dari sudut pandang subjektif saya, ini mempengaruhi keterbacaan kode cukup banyak.
Seperti disebutkan dalam contoh sebelumnya, Variable
itu sendiri bukanlah nama tipe, meskipun fitur baru membuatnya terlihat seperti nama secara sintaksis.
Pitiș kemudian menanyakan apa yang akan terjadi jika tidak ada konstruktor yang diberikan yang mengizinkan inferensi yang sesuai. Jawabannya adalah tidak ada inferensi yang diizinkan, karena inferensi dipicu oleh panggilan konstruktor . Tanpa panggilan konstruktor, tidak ada inferensi .
Ini mirip dengan menanyakan versi apa foo
yang disimpulkan di sini:
template <typename T> foo();
foo();
Jawabannya adalah kode ini ilegal, karena alasan yang disebutkan.
Jawaban MSalter
Ini, sejauh yang saya tahu, satu-satunya jawaban untuk memunculkan kekhawatiran yang sah tentang fitur yang diusulkan.
Contohnya adalah:
Variable var(num); // If equivalent to Variable<int> var(num),
Variable var2(var); // Variable<int> or Variable<Variable<int>> ?
Pertanyaan kuncinya adalah, apakah kompilator memilih konstruktor tipe-tersirat di sini atau konstruktor salinan ?
Mencoba kodenya, kita dapat melihat bahwa konstruktor salinan dipilih. Untuk memperluas contoh :
Variable var(num); // infering ctor
Variable var2(var); // copy ctor
Variable var3(move(var)); // move ctor
// Variable var4(Variable(num)); // compiler error
Saya tidak yakin bagaimana proposal dan versi baru standar menentukan ini; tampaknya ditentukan oleh "panduan deduksi," yang merupakan sedikit bahasa standar baru yang saya belum mengerti.
Saya juga tidak yakin mengapa var4
pemotongan tersebut ilegal; kesalahan kompilator dari g ++ tampaknya menunjukkan bahwa pernyataan tersebut sedang diurai sebagai deklarasi fungsi.