Brace geschlossene Initialisiererliste Konstruktor
-
29-09-2019 - |
Frage
Ich habe Klasse Phänotypen mit dem folgenden Konstruktor:
Phenotype(uint8 init[NUM_ITEMS]);
kann ich einen Phänotyp wie diese erstellen:
uint8 data[] = {0,0,0,0,0};
Phenotype p(data);
Aber ich einen Fehler, wenn ich versuche, eine wie diese zu erstellen:
Phenotype p = {0,0,0,0,0};
Ausgabe:
$ make
g++ -Wall -g main.cpp -std=c++0x
main.cpp: In function ‘int main(int, char**)’:
main.cpp:109: error: no matching function for call to ‘Phenotype::Phenotype(<brace-enclosed initializer list>)’
main.cpp:37: note: candidates are: Phenotype::Phenotype(uint8*)
Der Fehler scheint darauf hinzudeuten, dass es einen Weg gibt, einen Konstruktor zu definieren, die eine Klammer geschlossene Initialisiererliste nimmt. Wer weiß, wie dies geschehen könnte?
Lösung
Es kann nur für Aggregate erfolgen (Arrays und bestimmte Klassen. Entgegen der landläufigen Meinung, das funktioniert für viele nonpods auch). Schreiben einen Konstruktor, der sie nimmt, ist nicht möglich.
Da Sie es als „C ++ 0x“ markiert, dann ist dies möglich, wenn. Die magischen Worte „Initialisierer-Liste Konstruktor“. Dies geht wie
Phenotype(std::initializer_list<uint8> c) {
assert(c.size() <= std::size(m_array));
std::copy(c.begin(), c.end(), m_array);
}
// used like
Phenotype p1{1, 2, 3};
Phenotype p2({1, 3, 2}); // works too
Phenotype p3(1, 2, 3); // doesn't work
Allerdings wird eine solche Initialisierung Standard, um das Array konstruieren und verwenden dann den Zuweisungsoperator. Wenn Sie Geschwindigkeit und Sicherheit Ziel (Sie Kompilierung Fehler erhalten zu viele Initialisierer!), Können Sie auch einen gewöhnlichen Konstruktor mit einer variadische Vorlage verwenden.
Dies kann mehr generisch sein, als benötigt aber (oft ein initializer_list völlig ausreichend, vor allem für Normal ganze Zahlen). Es profitiert von perfekter Weiterleitung, so dass ein R-Wert Argument in ein Array-Element aufgebaut sein, bewegen kann
template<typename ...T>
Phenotype(T&&...t):m_array{ std::forward<T>(t)... } {
}
// used like
Phenotype p1{1, 2, 3};
Phenotype p2(1, 2, 3); // works too
Phenotype p3({1, 2, 3}); // doesn't work
Es ist eine harte Wahl!
Bearbeiten Korrektur funktioniert die letzten auch, da wir nicht den Konstruktor explicit
gemacht haben, so dass er den Kopierkonstruktor von Phenotype
verwenden kann, ein temporäres Phenotype
Objekt konstruieren und kopieren Sie sich über zu p3
. Aber das ist nicht das, was wir wirklich die Anrufe sein wollen würde:)
Andere Tipps
In C ++ 0x es scheint, dass Sie einen Konstruktor für diese erstellen können. Ich habe keine Erfahrung mit ihm selbst, aber es sieht aus wie Initialisiererliste-Konstruktor .
Ein Container kann einen Initialisierer-Liste Konstruktor wie diese implementieren:
template<class E> class vector {
public:
vector (std::initializer_list<E> s) // initializer-list constructor
{
reserve(s.size()); // get the right amount of space
uninitialized_copy(s.begin(), s.end(), elem); // initialize elements (in elem[0:s.size()))
sz = s.size(); // set vector size
}
// ... as before ...
};
Sie müssen die std :: initializer_list Vorlagentyp verwenden. Beispiel:
#include <iostream>
class X {
public:
X (std::initializer_list<int> list) {
for (auto i = list.begin(); i != list.end(); i++) {
std::cout << *i << std::endl;
}
}
};
int main () {
X x = {1,2,3,4,5};
}