2014-04-08 20 views
7

Tôi có lớp (bên thứ ba) không thể sao chép được. Tôi muốn khởi tạo một mảng của chúng. Đây là nỗ lực hết sức mình:Khởi tạo mảng C++ 11 với loại không thể sao chép được với hàm tạo rõ ràng

#include <array> 

class Thing 
{ 
public: 
    explicit Thing(int) {} 
    Thing(const Thing&) = delete; 
}; 

int main() 
{ 
    std::array<Thing, 1> things{{{100}}}; // error here 
}; 

GCC 4.7.2 nói:

error: converting to ‘std::array::value_type {aka Thing}’ from initializer list would use explicit constructor ‘Thing::Thing(int)’

OK, nhưng đó chính xác là những gì tôi muốn - sử dụng các nhà xây dựng rõ ràng. Làm thế nào tôi có thể diễn tả điều đó? Nếu tôi thực sự gọi bản thân hàm tạo, thì tôi sẽ gặp lỗi về hàm tạo bản sao đang bị xóa. Và tôi không thể sử dụng std::move() vì Thing không thể di chuyển được (và tôi không thể sửa đổi nó). Chỉ có duy nhất tôi đã tìm thấy cho đến nay là https://stackoverflow.com/a/15962814/4323 nhưng điều này là không mong muốn bởi vì nó là một bó thêm mã cộng với tôi cần phải đúc "lưu trữ" ở khắp mọi nơi tôi sử dụng nó (hoặc giữ một con trỏ riêng biệt với nó, mà cho biết thêm tôi không muốn).

Tôi muốn một giải pháp mang lại hiệu suất tối đa khi thực sự sử dụng Những thứ không có nhiều bản mẫu xấu xí.

+0

Bạn có thể thêm một hàm tạo rõ ràng có 'initializer_list '? –

+0

Tiêu chuẩn nói rằng đối với 'std :: mảng ', 'T' phải là MoveConstructible và MoveAssignable –

+0

Giải pháp trong chuỗi được liên kết không quá đau đớn. Tuy nhiên, bạn phải có một mức độ bất định (tôi không nghĩ rằng việc truy cập 'các thứ [n]' đối với 'std :: array' là khác nhau khi truy cập' các thứ [n] 'trong đó' Mọi thứ '; lưu trữ mà bạn sắp xếp mới) –

Trả lời

1

Tuy nhiên, một lần nữa, guaranteed copy elision đến giải cứu: biểu thức như Thing{100} không còn tạo một đối tượng mà chỉ chỉ định cách một số đối tượng khác (phần tử mảng của bạn) sẽ được tạo ra.

+0

Bạn có biết bất kỳ trình biên dịch nào có thể biên dịch mã ban đầu của tôi ngay bây giờ không? Tôi đã thử một vài điều trong https://godbolt.org/ (GCC thân, Clang 5.0), nhưng không ai trong số họ làm việc, ngay cả với '-std = c + + 17'. –

+0

Bạn phải thêm 'Điều': sau đó bạn nhận https://wandbox.org/permlink/a6QUxzY3O0xN1GJ6. –

1

Tôi đã thử thêm ctor di chuyển mặc định và di chuyển nhà điều hành chuyển nhượng, thay đổi khởi tạo một chút và nó biên dịch:

#include <array> 

class Thing 
{ 
public: 
    explicit Thing(int) {} 
    Thing(const Thing&) = delete; 
    Thing(Thing&&) = default; 
    Thing& operator=(Thing&&) = default; 
}; 

int main() 
{ 
    std::array<Thing, 1> things {{ Thing(100) }}; // error gone 
} 

EDIT: Tôi đã bỏ lỡ "bên thứ ba" một phần. Xin lỗi nếu điều này không giúp :)

+1

Có, làm cho lớp di chuyển sửa chữa nó, cũng như làm cho hàm tạo không rõ ràng. Nhưng tôi không thể làm được, bởi vì nó không phải là lớp của tôi. Tôi đoán tôi có thể quấn các lớp học với một có một constructor ngầm .... –

+0

Thêm một nhà xây dựng di chuyển không sửa chữa trường hợp mà các nhà điều hành [] mới được sử dụng. Ví dụ: 'auto things = new Thing [1] {100};' sẽ không hoạt động, và sẽ không có 'auto things = new Thing [1] {Thing {100}};'. – Alastair

-2

Bạn có thể sử dụng một std::vector:

std::vector<Thing> things; 
things.reserve(1); 
things.emplace_back(100); 

hoặc chỉ là một yếu tố boost::optional: C++ 17 của

boost::optional<Thing> thing; 
thing.emplace(100); 
Các vấn đề liên quan