Dapatkah std :: konstruktor rentang vektor meminta konversi eksplisit?

14

Apakah program berikut ini terbentuk dengan baik?

#include <vector>
struct A {
    explicit A(int) {}
};
int main() {
    std::vector<int> vi = {1, 2, 3, 4, 5};
    std::vector<A> va(vi.begin(), vi.end());
}

Menurut C ++ 17 [sequence.reqmts], persyaratan untuk

X u(i, j);

di mana Xadalah wadah urutan, adalah:

Takan EmplaceConstructiblemenjadi Xdari *i.

Namun, dalam paragraf sebelumnya dinyatakan bahwa:

idan jmenunjukkan iterator yang memenuhi persyaratan input iterator dan merujuk pada elemen yang secara implisit dapat dikonversi ke value_type,

Jadi menurut saya kedua persyaratan tersebut harus dipenuhi: tipe nilai dari rentang harus secara implisit dapat dikonversi ke tipe nilai kontainer, dan EmplaceConstructible harus dipenuhi (yang berarti pengalokasi harus dapat melakukan inisialisasi yang diperlukan) . Karena inttidak secara implisit dikonversi ke A, program ini harus dibuat dengan buruk.

Namun, yang mengejutkan, sepertinya dikompilasi di bawah GCC .

Brian
sumber
(Sebagai catatan, ini bukan hanya gcc: godbolt.org/z/ULeRDw )
Max Langhof
Dalam hal ini tidak diperlukan konversi implisit, karena konstruktor eksplisit sudah sesuai dengan tipenya. Saya pikir deskripsinya membingungkan, tetapi konstruksi eksplisit selalu lebih baik daripada konversi implisit sebelum konstruksi.
JHBonarius

Jawaban:

2

Ini hanya persyaratan untuk wadah urutan untuk mendukung konstruksi dari iterator yang memenuhi kriteria konvertibilitas implisit.

Ini tidak dengan sendirinya melarang kontainer berurutan untuk mendukung konstruksi dari iterator yang tidak memenuhi kriteria sejauh yang saya tahu 1 . Ada aturan eksplisit tentang itu:

Jika konstruktor ... dipanggil dengan tipe InputIterator yang tidak memenuhi syarat sebagai iterator input , maka konstruktor tidak akan berpartisipasi dalam resolusi kelebihan beban.

Tidak jelas apa "memenuhi syarat sebagai input iterator" berarti persis dalam konteksnya. Apakah ini cara informal untuk mengekspresikan Cpp17InputIterator, atau apakah ia mencoba merujuk persyaratan i dan j? Saya tidak tahu Apakah diizinkan atau tidak, standar tidak memiliki persyaratan ketat untuk mendeteksinya:

[container.requirements.general]

Perilaku fungsi anggota wadah tertentu dan panduan pengurangan tergantung pada apakah jenis memenuhi syarat sebagai iterator input atau pengalokasi. Sejauh mana suatu implementasi menentukan bahwa suatu jenis tidak dapat menjadi iterator input tidak ditentukan, kecuali bahwa sebagai tipe integral minimum tidak boleh memenuhi syarat sebagai iterator input. ...

Dengan interpretasi bahwa setiap Cpp17InputIterator "memenuhi syarat sebagai input iterator", program contoh tidak akan diminta untuk dibentuk dengan buruk. Tapi itu tidak dijamin akan terbentuk dengan baik.

1 Dalam kasus seperti itu, ini mungkin dianggap sebagai kualitas masalah implementasi untuk diperingatkan ketika mengandalkannya. Di sisi lain, pembatasan konversi implisit ini dapat dianggap sebagai cacat .


PS Ini mengkompilasi tanpa peringatan di Dentang (dengan libc ++) dan Msvc juga.

PPS Kata-kata ini tampaknya telah ditambahkan dalam C ++ 11 (yang alami, seperti yang juga konstruktor eksplisit juga diperkenalkan).

eerorika
sumber
1
Sangat tergantung pada apa yang "tidak memenuhi syarat sebagai input iterator" artinya. Tidak seperti di atas , itu tidak benar-benar mengatakan Cpp17InputIterator, jadi tidak jelas bagi saya apakah "dan merujuk pada elemen yang secara implisit dapat dikonversi menjadi value_type" termasuk dalam "input iterator". Jika ya, maka konstruktor tidak boleh berpartisipasi dalam resolusi kelebihan beban dan program harus dibentuk dengan buruk.
Max Langhof
1
Jadi, setiap kelas perpustakaan standar diizinkan memiliki konstruktor tambahan tanpa mengeluarkan diagnostik saat konstruktor ekstra tersebut digunakan? Secara intuitif itu kelihatannya salah bagi saya ...
Brian
@ Brian Saya tidak yakin apakah itu "konstruktor tambahan", tapi mungkin lebih "implementasi konstruktor spesifik yang memungkinkan lebih banyak ruang". Memeriksa setiap input mungkin memiliki dampak kinerja yang signifikan, jadi saya tidak tahu apakah itu akan menjadi cara untuk pergi ...
JHBonarius
@Brian Ini tentu akan menjadi ide yang buruk bahkan jika tidak secara eksplisit dianulir Dalam hal ini kami hanya mempertimbangkan apakah konstruktor yang diperlukan diizinkan untuk mendukung jenis iterator yang tidak perlu didukung. Dalam hal ini ada persyaratan eksplisit "tidak akan berpartisipasi" seperti yang ditunjukkan oleh Max, yang tentunya tidak akan mengizinkannya. Tetapi memang tidak jelas apa arti "memenuhi syarat sebagai input iterator" persis dalam konteksnya. Apakah ini cara informal untuk mengekspresikan Cpp17InputIterator, atau apakah ia mencoba merujuk pada persyaratan idan j? Saya tidak tahu
eerorika
2
1) Dalam C ++ kita menetapkan standar rendah. . 2) Konstruktor adalah fungsi anggota non-virtual . 3) Lihat LWG 3297 ; namun saya tidak terlalu yakin bahwa kita harus menghapus persyaratan konversi implisit.
TC