2014-04-08 5 views
7

Ich habe eine (Drittanbieter-) Klasse, die nicht kopierbar ist. Ich möchte eine Reihe von ihnen initialisieren. Hier ist mein bester Versuch:C++ 11 Array-Initialisierung mit einem nicht kopierbaren Typ mit expliziten Konstruktor

#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 sagt:

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

OK, aber das ist genau das, was ich will - den expliziten Konstruktor verwenden. Wie kann ich das ausdrücken? Wenn ich den Konstruktor tatsächlich selbst aufruft, erhalte ich eine Fehlermeldung über den Kopierkonstruktor, der gelöscht wird. Und ich kann std::move() nicht verwenden, weil Thing nicht beweglich ist (und ich kann es nicht ändern).

Die einzige Alternative, die ich bis jetzt gefunden habe, ist https://stackoverflow.com/a/15962814/4323, aber das ist unerwünscht, weil es eine Menge zusätzlichen Code plus ich muss den "Speicher" überall wo ich es verwende (oder einen separaten Zeiger darauf halten, was fügt hinzu Indirektion will ich nicht).

Ich möchte eine Lösung, die maximale Leistung gibt, wenn Sie die Dinge ohne eine Menge hässlichen Standard verwenden.

+0

Sie könnten einen expliziten Konstruktor hinzufügen, der 'initializer_list ' übernimmt? –

+0

Der Standard besagt, dass für 'std :: array ', 'T' muss MoveConstructible und MoveAssignable sein –

+0

Die Lösung im verknüpften Thread sieht nicht zu schmerzhaft. Du musst sowieso eine Umleitungsebene haben (ich denke nicht, dass der Zugriff auf 'sachen [n]' für 'std :: array' anders ist als der Zugriff auf' sachen [n] 'wo' Dinge * sachen; 'in die Speicher, den Sie Placement neu in) –

Antwort

1

Wieder einmal, C++ 17 des guaranteed copy elision kommt Die Rettung: ein Ausdruck wie Thing{100} nicht mehr erstellt ein Objekt, sondern gibt nur wie ein anderes Objekt (Ihr Array-Element) ist zu schaffen.

+0

Kennen Sie irgendeinen Compiler, der jetzt meinen ursprünglichen Code kompilieren kann? Ich habe ein paar Dinge in https://godbolt.org/ (GCC-Stamm, Clang 5.0) versucht, aber keiner von ihnen hat funktioniert, sogar mit "-std = C++ 17". –

+0

Sie müssen das 'Thing' hinzufügen: dann erhalten Sie https://wandbox.org/permlink/a6QUxzY3O0xN1GJ6. –

1

Ich habe versucht, die Standard-Bewegung Ctor Hinzufügen und Zuweisungsoperator bewegen, änderte sich die Initialisierung ein wenig und es kompiliert:

#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: Ich habe die „fremde“ Teil verpasst hatte. Sorry, wenn dies nicht :)

+1

Ja, wenn die Klasse beweglich gemacht wird, wird sie repariert, ebenso wie der Konstruktor nicht explizit gemacht wird. Aber ich kann auch nicht, weil es nicht meine Klasse ist. Ich denke, ich könnte die Klasse mit einem impliziten Konstruktor umschließen .... –

+0

Das Hinzufügen eines Verschiebungskonstruktors behebt nicht den Fall, in dem der neue Operator [] verwendet wird. Zum Beispiel: 'auto sachen = new Thing [1] {100};' wird nicht funktionieren, und auch nicht 'auto sachen = new Thing [1] {Sache {100}}; '. – Alastair

-2

Sie ein std::vector verwenden hilft:

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

oder für nur ein Element boost::optional:

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