Apa artinya "menggunakan ODR"?

92

Ini baru saja muncul dalam konteks pertanyaan lain .

Tampaknya fungsi anggota di templat kelas hanya dibuat jika digunakan dengan ODR. Bisakah seseorang menjelaskan apa sebenarnya artinya. The artikel wikipedia on One Definition Rule (ODR) tidak menyebutkan " ODR digunakan ".

Namun standar mendefinisikannya sebagai

Variabel yang namanya muncul sebagai ekspresi yang berpotensi dievaluasi digunakan odr kecuali itu adalah objek yang memenuhi persyaratan untuk muncul dalam ekspresi konstan (5.19) dan konversi lvalue-ke-rvalue (4.1) segera diterapkan.

di [basic.def.odr].

Sunting: Rupanya ini adalah bagian yang salah dan seluruh paragraf berisi banyak definisi untuk hal yang berbeda. Ini mungkin yang relevan untuk fungsi anggota templat kelas:

Fungsi non-kelebihan beban yang namanya muncul sebagai ekspresi yang berpotensi dievaluasi atau anggota dari sekumpulan fungsi kandidat, jika dipilih oleh resolusi kelebihan beban saat dirujuk dari ekspresi yang berpotensi dievaluasi, digunakan odr, kecuali jika itu adalah virtual murni fungsi dan namanya tidak terkualifikasi secara eksplisit.

Namun saya tidak mengerti, bagaimana aturan ini bekerja di beberapa unit kompilasi? Apakah semua fungsi anggota dibuat instance-nya jika saya secara eksplisit membuat instance template kelas?

Sarien
sumber
2
Perhatikan bahwa [basic.def.odr] / 6 berlaku untuk fungsi anggota templat kelas "Bisa ada lebih dari satu definisi [...]"
dyp
3
"Apakah semua fungsi anggota dibuat instance-nya jika saya secara eksplisit membuat instance template kelas?" Ya, lihat [temp.explicit] / 8 + 9
dyp

Jawaban:

71

Ini hanya definisi sewenang-wenang, yang digunakan oleh standar untuk menentukan kapan Anda harus memberikan definisi untuk suatu entitas (bukan hanya deklarasi). Standar tidak mengatakan hanya "bekas", karena ini dapat ditafsirkan secara berbeda tergantung pada konteksnya. Dan beberapa penggunaan ODR tidak benar-benar sesuai dengan apa yang biasanya diasosiasikan dengan "use"; misalnya, fungsi virtual selalu digunakan ODR kecuali ia murni, meskipun sebenarnya tidak dipanggil di mana pun dalam program.

Definisi lengkapnya ada di §3.2 , paragraf kedua, meskipun ini berisi referensi ke bagian lain untuk melengkapi definisi tersebut.

Berkenaan dengan template, penggunaan ODR hanyalah sebagian dari pertanyaan; bagian lainnya adalah instansiasi. Secara khusus, §14.7 mencakup ketika sebuah templat digunakan. Tetapi keduanya terkait: meskipun teks dalam §14.7.1 (instansiasi implisit) cukup panjang, prinsip dasarnya adalah bahwa template hanya akan dibuat instance-nya jika digunakan, dan dalam konteks ini, digunakan berarti digunakan ODR. Jadi, fungsi anggota template kelas hanya akan dibuat instance-nya jika dipanggil, atau jika itu virtual dan kelas itu sendiri dibuat instance-nya. Standar itu sendiri mengandalkan hal ini di banyak tempat: std::list<>::sortpenggunaan <pada masing-masing elemen, tetapi Anda dapat membuat contoh daftar di atas jenis elemen yang tidak mendukung <, selama Anda tidak memanggilnya sort.

James Kanze
sumber
dapatkah penggunaan ODR tumpang tindih dengan "materialized temporaries"?
v.oddou
23

Sederhananya, odr-used berarti sesuatu (variabel atau fungsi) digunakan dalam konteks di mana definisi itu harus ada.

misalnya,

struct F {
   static const int g_x = 2;
};

int g_x_plus_1 = F::g_x + 1; // in this context, only the value of g_x is needed.
                             // so it's OK without the definition of g_x

vector<int>  vi;
vi.push_back( F::g_x );      // Error, this is odr-used, push_back(const int & t) expect
                             // a const lvalue, so it's definition must be present

Catatan, push_back di atas diteruskan di MSVC 2013, perilaku ini tidak sesuai standar, baik gcc 4.8.2 dan clang 3.8.0 gagal, pesan kesalahannya adalah: referensi tidak ditentukan ke `K :: g_x '

zhaorufei
sumber
Apakah mungkin untuk menggunakan odr-menggunakan anggota data statis seperti vi.push_back( F::g_x );di c ++?
Rankaba
Tetapi nilai r juga bisa diteruskan ke const int&? Mungkinkah anggota konstanta statis diubah menjadi nilai r?
scottxiao
8
+1 untuk kalimat pembuka yang ringkas: "Dalam kata sederhana, odr-used berarti sesuatu (variabel atau fungsi) digunakan dalam konteks di mana definisi itu harus ada."
Paul Masri-Stone
1
Saya tidak mengerti bagaimana Anda menyusun kode itu. Apakah mereka berada di TU yang sama? Jika ya, F :: g_x sudah didefinisikan sebelumnya push_back, tentu saja akan lolos. Bukan?
Lewis Chan
1
@bigxiao " a rvalue juga bisa diteruskan " Ya dan objek sementara dibuat oleh kompilator dan referensi terikat ke objek itu. OTOH saat meneruskan nilai l yang berarti meneruskan objek yang dirujuk oleh evaluasi nilai l: saat Anda meneruskan nilai l, Anda dapat mengharapkan parameter dalam fungsi untuk merujuk ke objek yang benar. Kompilator tidak akan membuat file sementara. Jika Anda ingin yang sementara, buatlah dengan operator+.
wonderguy