Điều này sẽ không hoạt động như đã nêu, bởi vì list.begin()
có loại const T *
và không có cách nào bạn có thể di chuyển từ một đối tượng không đổi. Các nhà thiết kế ngôn ngữ có lẽ đã làm như vậy để cho phép danh sách trình khởi tạo chứa các hằng số chuỗi chẳng hạn, từ đó nó sẽ không thích hợp để di chuyển.
Tuy nhiên, nếu bạn đang ở trong tình huống mà bạn biết rằng danh sách trình khởi tạo có chứa các biểu thức rvalue (hoặc bạn muốn buộc người dùng viết các biểu thức đó) thì có một mẹo sẽ làm cho nó hoạt động (Tôi đã lấy cảm hứng từ câu trả lời của Sumant cho này, nhưng giải pháp là cách đơn giản hơn một). Bạn cần các phần tử được lưu trữ trong danh sách trình khởi tạo không phải là T
các giá trị, mà là các giá trị đóng gói T&&
. Sau đó, ngay cả khi bản thân các giá trị đó const
đủ điều kiện, chúng vẫn có thể truy xuất giá trị có thể sửa đổi.
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
};
Bây giờ thay vì khai báo một initializer_list<T>
đối số, bạn khai báo một initializer_list<rref_capture<T> >
đối số. Đây là một ví dụ cụ thể, liên quan đến một vectơ của các std::unique_ptr<int>
con trỏ thông minh, mà chỉ các ngữ nghĩa chuyển động được xác định (vì vậy bản thân các đối tượng này không bao giờ có thể được lưu trữ trong danh sách trình khởi tạo); nhưng danh sách trình khởi tạo bên dưới biên dịch mà không có vấn đề gì.
#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;
}
Một câu hỏi cần có câu trả lời: nếu các phần tử của danh sách bộ khởi tạo phải là giá trị thực (trong ví dụ chúng là giá trị x), thì ngôn ngữ có đảm bảo rằng thời gian tồn tại của các dấu tạm thời tương ứng kéo dài đến thời điểm chúng được sử dụng không? Thành thật mà nói, tôi không nghĩ rằng phần 8.5 có liên quan của tiêu chuẩn đề cập đến vấn đề này. Tuy nhiên, đọc 1,9: 10, có vẻ như biểu thức đầy đủ có liên quan trong mọi trường hợp đều bao gồm việc sử dụng danh sách trình khởi tạo, vì vậy tôi nghĩ rằng không có nguy cơ bị treo các tham chiếu rvalue.
initializer_list<T>
là không -const. Giống như,initializer_list<int>
đề cập đếnint
các đối tượng. Nhưng tôi nghĩ đó là một khiếm khuyết - mục đích là các trình biên dịch có thể cấp phát tĩnh một danh sách trong bộ nhớ chỉ đọc.