Bu belirtildiği gibi çalışmaz, çünkü list.begin()
türü const T *
vardır ve sabit bir nesneden hareket etmenin bir yolu yoktur. Dil tasarımcıları muhtemelen bunu, başlatıcı listelerinin, taşınması uygun olmayan örneğin dize sabitleri içermesine izin vermek için yaptılar.
Ancak, başlatıcı listesinin rvalue ifadeleri içerdiğini bildiğiniz bir durumdaysanız (veya kullanıcıyı bunları yazmaya zorlamak istiyorsanız) o zaman işe yarayacak bir numara var (Sumant'ın cevabından ilham aldım. bu, ancak çözüm bundan çok daha basit). Başlatıcı listesinde depolanan öğelerin T
değerler değil , kapsayıcı değerler olması gerekir T&&
. Daha sonra bu değerlerin kendileri const
nitelikli olsa bile , yine de değiştirilebilir bir değer elde edebilirler.
template<typename T>
class rref_capture
{
T* ptr;
public:
rref_capture(T&& x) : ptr(&x) {}
operator T&& () const { return std::move(*ptr); }
};
Şimdi bir initializer_list<T>
argüman bildirmek yerine, bir argüman ilan edersiniz initializer_list<rref_capture<T> >
. Burada, std::unique_ptr<int>
sadece hareket anlamının tanımlandığı akıllı işaretçilerden oluşan bir vektörü içeren somut bir örnek var (bu nedenle bu nesnelerin kendileri asla bir başlatıcı listesinde saklanamaz); ancak aşağıdaki başlatıcı listesi sorunsuz bir şekilde derlenir.
#include <memory>
#include <initializer_list>
class uptr_vec
{
typedef std::unique_ptr<int> uptr;
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;
}
Bir sorunun cevaba ihtiyacı var: Eğer başlatıcı listesinin elemanları doğru prvalues olması gerekiyorsa (örnekte bunlar xdeğerlerse), dil karşılık gelen geçicilerin yaşam süresinin kullanıldıkları noktaya kadar uzamasını sağlıyor mu? Açıkçası, standardın ilgili bölüm 8.5'in bu konuyu ele aldığını sanmıyorum. Bununla birlikte, 1.9: 10 okunduğunda , her durumda ilgili tam ifadenin başlatıcı listesinin kullanımını kapsadığı görülüyor , bu nedenle rvalue referanslarının sarkma tehlikesi olmadığını düşünüyorum.
initializer_list<T>
sürekli olmadığını tanımlar. Gibi, nesneleriinitializer_list<int>
ifade ederint
. Ama bence bu bir kusur - derleyicilerin salt okunur bellekte statik olarak bir liste ayırması amaçlanıyor.