(), {} and std::initializer_list
1. Commons and distinctions between () and {}
  
    |  | () | {} | 
  
    | Commons | Direct initialization 
    int x(3);
    int x{3};
    std::string name("Some Name");
    std::string name{"Some Name"};
    int* y = new int(1);
    int* y = new int{1};
    
 Call constructors
 
    MyClass mc(1);
    MyClass mc{1}; // If no initializer list constructor exists.
    
 | 
  
    | Distincetions | Narrowing Conversions | int pi(3.14);  // OK -- pi == 3.
 | int pi{3.14};  // Compile error: narrowing conversion.
 | 
  
    | Uniform Initialization | std::vector v(100, 1);  // A vector containing 100 items: All 1s.
 | std::vector v{100, 1};  // A vector containing 2 items: 100 and 1.
 | 
2. std:: initializer_list
Using std::initializer_list allows a class to be constructed with a list of values, providing flexibility and ease of initialization.
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 
 | template<typename T>struct S {
 S(std::initializer_list<T> data) : _data(data) {
 std::cout << "initializer_list contructor called\n";
 }
 S(T a, T b, T c) {
 std::cout << "3 params contructor called\n";
 }
 private:
 std::initializer_list<T> _data;
 };
 
 int main() {
 S<int> s1{1, 2, 3};
 S<int> s2(1, 2, 3);
 S<int> s3{1.1, 2.2, 3.3};
 return 0;
 }
 
 | 
{} provides a more safer way(prevent type conversion) for initialization. In situations where {} and () are equivalent, we should choose {} over ();
References