Brace-joint initialiseur constructeur de liste
-
29-09-2019 - |
Question
Je classe Phénotype avec le constructeur suivant:
Phenotype(uint8 init[NUM_ITEMS]);
Je peux créer un Phénotype comme ceci:
uint8 data[] = {0,0,0,0,0};
Phenotype p(data);
Mais je reçois une erreur lorsque je tente de créer un comme ceci:
Phenotype p = {0,0,0,0,0};
Sortie:
$ 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*)
L'erreur semble indiquer qu'il existe un moyen de définir un constructeur qui prend un joint accolades initialiseur liste. Est-ce que quelqu'un sait comment cela pourrait se faire?
La solution
Il ne peut être fait pour les agrégats (tableaux et certaines classes. Contrairement à la croyance populaire, cela fonctionne pour beaucoup nonpods aussi). L'écriture d'un constructeur qui les prend est impossible.
Depuis que vous avez taguée comme « C ++ 0x », alors cela est possible cependant. Les mots magiques est « constructeur initialiseur-list ». Cela va comme
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
Toutefois, cette initialisation sera par défaut construire le tableau, puis utilisez l'opérateur d'affectation. Si vous visez pour la vitesse et la sécurité (vous obtenez des erreurs lors de la compilation pour un trop grand nombre initializers!), Vous pouvez aussi utiliser un constructeur ordinaire avec un modèle variadique.
Cela peut être plus générique que nécessaire si (souvent un initializer_list suffit complètement, en particulier pour les entiers simples). Il bénéficie de la transmission parfaite, de sorte que l'argument de rvalue peut être construit déplacer dans un élément de tableau
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
Il est un choix difficile!
Modifier Correction, le dernier fonctionne aussi, comme nous ne faisions pas le constructeur explicit
, il peut donc utiliser le constructeur de copie de Phenotype
, la construction d'un objet Phenotype
temporaire et le copier sur p3
. Mais ce n'est pas ce que nous voulons vraiment les appels à:)
Autres conseils
En C ++ 0x il semble que vous pouvez créer un constructeur pour cela. Je n'ai aucune expérience avec moi-même, mais il semble que ça s'appelle initialiseur liste constructeur.
Un conteneur peut mettre en œuvre un constructeur liste d'initialiseur comme ceci:
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 ...
};
Vous devez utiliser le type de modèle std :: initializer_list. Exemple:
#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};
}