Templat argumen default

151

Jika saya diizinkan melakukan hal berikut:

template <typename T = int>
class Foo{
};

Mengapa saya tidak diizinkan melakukan hal berikut di main?

Foo me;

Tetapi saya harus menentukan yang berikut:

Foo<int> me;

C ++ 11 memperkenalkan argumen templat default dan saat ini mereka sulit dipahami oleh pemahaman lengkap saya.

pengguna633658
sumber

Jawaban:

188

Kamu harus melakukan:

Foo<> me;

Argumen templat harus ada tetapi Anda dapat membiarkannya kosong.

Anggap saja seperti fungsi foodengan satu argumen default. Ekspresi footidak akan menyebutnya, tetapi foo()akan. Sintaks argumen masih harus ada di sana. Ini konsisten dengan itu.

Joseph Mansfield
sumber
4
@ Patby Saya kira itu akan membuat beberapa komplikasi yang tidak perlu jika Foo mungkin pengidentifikasi template atau mungkin instantiasi eksplisit tergantung pada apakah ada argumen default. Lebih baik menjaga sintaksis Instansiasi eksplisit. Anggap saja seperti fungsi foodengan satu parameter standar. Anda tidak dapat menyebutnya seperti foo, Anda menyebutnya dengan foo(). Masuk akal untuk menjaga ini konsisten.
Joseph Mansfield
2
@ sftrabbit tetapi Anda tidak dapat memanggil fungsi tanpa argumen seperti foo; Anda dapat memberi nama kelas tanpa argumen Foo.
Seth Carnegie
4
@aschepler Dengan suatu fungsi, argumen templat dapat disimpulkan dari argumen fungsi. Dengan sebuah kelas, tidak mungkin untuk memutuskan, apakah Anda bermaksud kelas template dengan argumen default atau kelas non template.
Olaf Dietsche
21
@OlafDietsche tetapi Anda tidak dapat memiliki kelas templat dan kelas non-templat dengan nama yang sama, sehingga kompiler harus dapat memutuskan dengan hanya melihat apa namanya.
Seth Carnegie
7
@ Patby Komite standar bertanya pada diri sendiri, saya kira. Sekarang, dengan C ++ 17, <>tidak diperlukan lagi dalam hal ini. Lihat jawaban saya untuk lebih jelasnya.
Paolo M
53

Dengan C ++ 17, Anda memang bisa.

Fitur ini disebut pengurangan argumen templat kelas dan menambahkan lebih banyak fleksibilitas dengan cara Anda dapat mendeklarasikan variabel tipe templated .

Begitu,

template <typename T = int>
class Foo{};

int main() {
    Foo f;
}

sekarang kode C ++ legal .

Paolo M
sumber
5
Aneh. Baru saja mencobanya di proyek C ++ 17 saya dan tidak berhasil: "templat tipe placeholder 'const MyType' harus diikuti oleh declarator-id sederhana". Saya menggunakan GCC 7.3.0.
Silicomancer
1
@ Silicomancer Sulit untuk mengatakan tanpa melihat kode dan baris perintah Anda ... Mungkin Anda berurusan dengan pointer seperti di sini ?
Paolo M
1
Dentang sepertinya tidak menerimanya? coliru.stacked-crooked.com/a/c5d3c0f90ed263c2
Borgleader
1
@Borgleader Rupanya, Coliru menggunakan dentang 5.0. Menilai dengan ini , itu harus mendukung pengurangan argumen template C ++ 17, tapi jelas id tidak. Jika Anda mencoba contoh yang sama di wandbox menggunakan clang 7.0, ia berfungsi dengan sempurna.
Paolo M
2
@ PaoloM Oh keren, senang tahu itu hanya masalah versi kompiler. Terima kasih telah melihat ini.
Borgleader
19

Anda tidak diizinkan melakukan itu tetapi Anda bisa melakukan ini

typedef Foo<> Fooo;

dan kemudian lakukan

Fooo me;
g24l
sumber
apakah ada perbedaan dalam hal ini dengan tipe default dan:, typedef Foo<float> Fooo;tanpa tipe default?
qrikko
5
Cara C ++ 11-ish akan mengatakanusing Fooo = Foo<>;
Adrian W
18

Anda dapat menggunakan yang berikut ini:

Foo<> me;

Dan telah intmenjadi argumen template Anda. Kurung sudut diperlukan dan tidak dapat dihilangkan.

Andy Prowl
sumber
Masuk akal dan terima kasih tetapi, seperti yang disebutkan di bawah ini, mengapa tipe yang ditentukan tidak ada?
user633658
@ user633658: Apakah maksud Anda "ketik specifier"? Saya tidak yakin saya mengerti
Andy Prowl
Lagi pula, mengenai alasan di balik perlunya kurung sudut kosong, saya hanya bisa membuat dugaan, dan mereka semua mengesampingkan kemungkinan ambiguitas dengan penggunaan nama templat saja, tetapi saya harus mengakui bahwa saya tidak tahu persis alasan
Andy Prowl
Saya sangat curiga persyaratan untuk <> adalah untuk mengaktifkan parser kompiler untuk menentukan bahwa Anda merujuk ke kelas templated yang disebut foo, bukan sesuatu yang disebut foo.
Mac