Disons que j'ai la classe c_student
avec plusieurs membres et aucun constructeur:
c_student( std::initializer_list <???>) = default; << Pseudo-code only!
Ce code fonctionne bien, mais disons que je veux définir des constructeurs personnalisés à l'intérieur de la classe:
47_object_initialization.cpp:32:34: error: could not convert â{"Luke ", 420}â from â<brace-enclosed initializer list>â to âc_studentâ 32 | c_student stud_c = {"Luke ",420}; | ^ | | | <brace-enclosed initializer list>
Si je les ajoute à la classe, le compilateur se plaint que:
c_student (std::string n):name(n){}; c_student() = default;
Je veux continuer à utiliser le constructeur par défaut pour {} et j'ai donc besoin d'écrire quelque chose comme:
#include <iostream> #include <string> #include <initializer_list> #include <typeinfo> class c_student{ // private: public: std::string name = "John"; int mark = 5; std::string second_name="Doe"; void print(){ std::cout << name <<" " << second_name << " : "<< mark<<"\n"; } }; int main(){ c_student stud_c = {"Luke ",420}; stud_c.print(); c_student stud_d = {"Mark "}; stud_d.print(); }
Mais je ne peux pas comprendre exactement comment. Quelqu'un pourrait-il attirer mon attention sur la bonne page de référence du RPC?
3 Réponses :
Ce n'est malheureusement pas possible. La raison pour laquelle votre code a fonctionné à l'origine est due à l' initialisation de l'agrégat . Dès que vous avez créé un constructeur défini par l'utilisateur, votre classe n'est plus un type d'agrégat
Un agrégat est l'un des types suivants:
- type de classe qui a
- aucun constructeur déclaré par l'utilisateur
Êtes-vous sûr? Peut-être que ce n'est possible que dans les normes ultérieures, mais il y a quelques informations connexes ici: stackoverflow.com/questions/21941967/...
@SvenNilsson La raison pour laquelle le code fonctionne est qu'il a fourni un constructeur défini par l'utilisateur pour B
, ce que l'OP est libre de faire ici aussi. Cependant, l'OP souhaite ici "ramener" le comportement d'initialisation default
agrégats, ce qui, comme le mentionne la norme, n'est pas possible. Ils devraient définir un constructeur défini par l'utilisateur pour émuler ce type de comportement, ce qui mine le comportement généré default
compilateur.
OK, je comprends. Vous avez raison, mais il existe une solution de contournement ...
Vous pouvez utiliser l'initialisation d'accolades pour obtenir ce que vous voulez en remplaçant tous les constructeurs par le suivant:
c_student (std::string name = "John", int mark = 5, std::string second_name = "Doe") : name(name), mark(mark), second_name(second_name) {};
De plus, vous pouvez supprimer les initialiseurs de membres par défaut car la seule façon de construire un c_student
leur donnera les valeurs par défaut si elles ne sont pas fournies.
Voici une démo .
Sympa et efficace. Cependant, que se passe-t-il si l'ordre des éléments de la liste est différent, comme {"First", "Last", 20}
?
@AdrianMole Sans les initialiseurs désignés par C ++ 20, il n'y a aucun moyen de se moquer de l'ordre des paramètres.
Vous pouvez fournir des constructeurs explicites (et séparés) avec différents ordres d'arguments.
@AdrianMole Parfois, mais je pense que tous les arguments devraient être de types différents. Par exemple, comment c_student("Adrian")
vous l' c_student("Adrian")
entre c_student("Adrian")
? Est-ce le premier ou le deuxième nom? Hmm, en fait, UDL fonctionnerait comme un correctif pour cela, mais c'est beaucoup de travail juste pour différents ordres de constructeur.
Vous pouvez ajouter un autre constructeur défini par l'utilisateur pour gérer la liste d'initialisation avec deux entrées (et continuer à ajouter de tels constructeurs pour chaque taille et ordre de liste possibles). Les éléments suivants se compilent et fonctionnent comme prévu:
#include <iostream> #include <string> class c_student { private: std::string name = "John"; int mark = 5; std::string second_name = "Doe"; public: void print() { std::cout << name << " " << second_name << " : " << mark << "\n"; } c_student(std::string n) : name(n) { } // Called for initializer list {"xxx"} c_student(std::string n, int m) : name(n), mark(m) { } // Called for list {"xxx", m} c_student(std::string n, std::string s, int m) : name(n), mark(m), second_name(s) { } // Called for list {"xxx", "yyy", m} c_student() = default; }; int main() { c_student stud_c = { "Luke", 420 }; stud_c.print(); c_student stud_d = { "Mark" }; stud_d.print(); c_student stud_e = { "John", "Smith", 333 }; stud_e.print(); return 0; }