2014-04-08 24 views
7

Mam klasę (innej firmy), która nie jest dostępna do kopiowania. Chciałbym zainicjować ich szereg. Oto moja najlepsza próba:Inicjalizacja tablic C++ 11 z typem nie do kopiowania z jawnym konstruktorem

#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 mówi:

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

OK, ale to jest dokładnie to, co chcę - aby użyć wyraźne konstruktora. Jak mogę to wyrazić? Jeśli sam wywołuję konstruktora, pojawia się błąd dotyczący usunięcia konstruktora kopiowania. I nie mogę używać std::move(), ponieważ Thing nie jest ruchomy (i nie mogę go modyfikować).

Jedyną alternatywą, którą znalazłem do tej pory, jest https://stackoverflow.com/a/15962814/4323, ale jest to niepożądane, ponieważ jest to pęczek dodatkowego kodu i muszę przesyłać "pamięć" wszędzie, gdzie go używam (lub zachować oddzielny wskaźnik do niego, który dodaje w kierunku, którego nie chcę).

Chcę rozwiązania, które zapewnia maksymalną wydajność podczas korzystania z Rzeczy bez wielu brzydkich elementów.

+0

Można dodać jawny konstruktor, który pobiera 'initializer_list '? –

+0

Standard mówi, że dla 'std :: array ', 'T' musi być MoveConstructible i MoveAssignable –

+0

Rozwiązanie w połączonym wątku nie wygląda zbyt boleśnie. Musisz i tak mieć poziom niezależności (nie sądzę, że dostęp do 'rzeczy [n]' dla 'std :: array' jest inny niż dostęp do' rzeczy [n] 'gdzie' Things * things; 'wskazuje na miejsce, w którym wstawiłeś nowe) –

Odpowiedz

1

raz kolejny, C++ 17 na guaranteed copy elision przychodzi ratowanie: wyrażenie takie jak Thing{100} nie tworzy już obiektu, lecz jedynie określa inny obiekt (twój element tablicy) ma zostać stworzony.

+0

Czy znasz jakiś kompilator, który może teraz skompilować mój oryginalny kod? Próbowałem kilku rzeczy w https://godbolt.org/ (GCC trunk, Clang 5.0), ale żaden z nich nie działał, nawet z '-std = C++ 17'. –

+0

Musisz dodać 'Thing': dostaniesz https://wandbox.org/permlink/a6QUxzY3O0xN1GJ6. –

1

Próbowałem dodając domyślny konstruktor i przenieść ruch operatora przypisania, zmienił inicjalizacji trochę i kompiluje:

#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: ja brakowało „osób trzecich” część. Przepraszam, jeśli to nie pomoże :)

+1

Tak, dzięki czemu klasa jest ruchoma naprawia ją, podobnie jak nie czyni jawnym konstruktora. Ale ja też nie mogę, bo to nie moja klasa. Sądzę, że mógłbym zawinąć klasę z tym, który ma niejawny konstruktor ... –

+0

Dodanie konstruktora ruchu nie rozwiązuje przypadku, w którym używany jest nowy operator []. Na przykład: 'auto things = new Thing [1] {100};' nie zadziała, a także 'auto things = new Thing [1] {Thing {100}};'. – Alastair

-2

Można użyć std::vector:

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

lub tylko dla jednego elementu boost::optional:

boost::optional<Thing> thing; 
thing.emplace(100);