Reputation: 29
Let's say I have c_student
class with several members and no constructors:
#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();
}
This code works fine, but let's say I want to define custom constructors inside the class:
c_student (std::string n):name(n){};
c_student() = default;
If I add them to class, the compiler complains that:
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>
I want to keep using default constructor for {} and so need to write something like:
c_student( std::initializer_list <???>) = default; << Pseudo-code only!
But can't get how exactly. Could anyone points my attention on the right page of CPP reference?
Upvotes: 2
Views: 1710
Reputation: 51884
You can add another user-defined constructor to handle the initializer list with two entries (and keep adding such constructors for each possible list size and order). The following compiles and works as expected:
#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;
}
Upvotes: 1
Reputation: 60278
You can use brace-initialization to achieve what you want by replacing all the constructors with the following one:
c_student (std::string name = "John", int mark = 5, std::string second_name = "Doe")
: name(name), mark(mark), second_name(second_name) {};
Also, you can remove the default member initializers since the only way to construct a c_student
will give them the default values if they are not provided.
Here's a demo.
Upvotes: 2
Reputation: 118001
This is unfortunately not possible. The reason your code originally worked is due to Aggregate initialization. As soon as you created a user-defined constructor, your class is no longer an aggregate type
An aggregate is one of the following types:
- class type that has
-- no user-declared constructors
Upvotes: 2