Ini tidak akan berfungsi seperti yang dinyatakan, karena list.begin()
memiliki tipe const T *
, dan tidak mungkin Anda dapat berpindah dari objek konstan. Perancang bahasa mungkin membuatnya sedemikian rupa untuk memungkinkan daftar penginisialisasi berisi, misalnya konstanta string, yang darinya tidak pantas untuk dipindahkan.
Namun, jika Anda berada dalam situasi di mana Anda tahu bahwa daftar penginisialisasi berisi ekspresi rvalue (atau Anda ingin memaksa pengguna untuk menuliskannya) maka ada trik yang akan membuatnya bekerja (saya terinspirasi oleh jawaban Sumant untuk ini, tetapi solusinya jauh lebih sederhana dari yang itu). Anda memerlukan elemen yang disimpan dalam daftar penginisialisasi bukan T
nilai, tetapi nilai yang merangkum T&&
. Kemudian, meskipun nilai itu sendiri const
memenuhi syarat, mereka masih dapat mengambil rvalue yang dapat dimodifikasi.
template<typename T>
class rref_capture
{
T* ptr;
public:
rref_capture(T&& x) : ptr(&x) {}
operator T&& () const { return std::move(*ptr); } // restitute rvalue ref
};
Sekarang, alih-alih mendeklarasikan initializer_list<T>
argumen, Anda mendeklarasikan initializer_list<rref_capture<T> >
argumen. Berikut adalah contoh konkret, yang melibatkan vektor std::unique_ptr<int>
pointer pintar, yang hanya mendefinisikan semantik bergerak (jadi objek ini sendiri tidak akan pernah bisa disimpan dalam daftar penginisialisasi); namun daftar penginisialisasi di bawah ini dapat dikompilasi tanpa masalah.
#include <memory>
#include <initializer_list>
class uptr_vec
{
typedef std::unique_ptr<int> uptr; // move only type
std::vector<uptr> data;
public:
uptr_vec(uptr_vec&& v) : data(std::move(v.data)) {}
uptr_vec(std::initializer_list<rref_capture<uptr> > l)
: data(l.begin(),l.end())
{}
uptr_vec& operator=(const uptr_vec&) = delete;
int operator[] (size_t index) const { return *data[index]; }
};
int main()
{
std::unique_ptr<int> a(new int(3)), b(new int(1)),c(new int(4));
uptr_vec v { std::move(a), std::move(b), std::move(c) };
std::cout << v[0] << "," << v[1] << "," << v[2] << std::endl;
}
Satu pertanyaan memang membutuhkan jawaban: jika elemen dari daftar penginisialisasi harus merupakan prvalues yang benar (dalam contoh ini adalah xvalues), apakah bahasa memastikan bahwa masa pakai temporer yang sesuai meluas ke titik di mana mereka digunakan? Sejujurnya, menurut saya bagian 8.5 dari standar yang relevan tidak membahas masalah ini sama sekali. Namun, membaca 1.9: 10, tampaknya ekspresi lengkap yang relevan dalam semua kasus mencakup penggunaan daftar penginisialisasi, jadi saya rasa tidak ada bahaya menggantung referensi nilai r.
initializer_list<T>
adalah non -const. Seperti,initializer_list<int>
mengacu padaint
objek. Tapi saya pikir itu adalah cacat - itu dimaksudkan agar kompiler dapat mengalokasikan daftar secara statis dalam memori hanya baca.