Skip to content

Latest commit

 

History

History
127 lines (91 loc) · 5.16 KB

File metadata and controls

127 lines (91 loc) · 5.16 KB

Uniform initialization


C++98/03 initialization


int a;          // undefined value
int b(5);       // direct initialization, b = 5
int c = 10;     // copy initialization, c = 10
int d = int();  // default initialization, d = 0
int e();        // function declaration - "most vexing parse"

int values[] = { 1, 2, 3, 4 };  // brace initialization of aggregate
int array[] = { 1, 2, 3.5 };    // C++98 - ok, implicit type narrowing

struct P { int a, b; };
P p = { 20, 40 };                  // brace initialization of POD

std::complex<double> c(4.0, 2.0);  // initialization of classes

std::vector<std::string> names;    // no initialization for list of values
names.push_back("John");
names.push_back("Jane");

C++11 initialization with {}


int a;          // still undefined value
int b{5};       // brace initialization, b = 5
int c{};        // brace initialization, c = 0

int values[] = { 1, 2, 3, 4 };  // brace initialization of aggregate
int array[] = { 1, 2, 3.5 };    // C++11: error - implicit type narrowing

struct P { int a, b; };
P p = { 20, 40 };               // brace initialization of POD

std::complex<double> c{4.0, 2.0};   // brace initialization calls adequate c-tor

std::vector<std::string> names = { "John", "Jane" };  // brace initialization of vector

Rationale: eliminate problematic initialization cases from C++98, initialization of STL containers, have one universal way of initialization.


In-class initialization of non-static variables

struct Foo
{
    Foo() {}
    Foo(std::string a) : a_(a) {}
    void print() { std::cout << a_ << std::endl; }

private:
   std::string a_ = "Foo";              // C++98: error, C++11: OK
   static const unsigned VALUE = 20u;   // C++98: OK, C++11: OK
};

Foo().print();          // Foo
Foo("Bar").print();     // Bar

std::initializer_list<T>

auto values = {1, 2, 3, 4, 5};   // values is std::initializer_list<int>
std::vector<int> v = {1, 2, -3}; // creates a vector from
                                 // std::initializer_list<int>
  • Defined in initializer_list header
  • Elements are kept in an array
  • Elements are immutable
  • Elements must be copyable
  • Have limited interface and access via iterators - begin(), end(), size()
  • Should be passed to functions by value

Constructor priority


template<class Type>
class Bar {
    std::vector<Type> values_;
public:
    Bar(std::initializer_list<Type> values) : values_(values) {}
    Bar(Type a, Type b) : values_{a, b} {}
};

Bar<int> c = {1, 2, 5, 51};   // calls std::initializer_list c-tor
Bar<int> d{1, 2, 5, 51};      // calls std::initializer_list c-tor
Bar<int> e = {1, 2};          // calls std::initializer_list c-tor
Bar<int> f{1, 2};             // calls std::initializer_list c-tor
Bar<int> g(1, 2);             // calls Bar(Type a, Type b) c-tor
Bar<int> h = {};              // calls std::initializer_list c-tor
                              // or default c-tor if exists
Bar<std::unique_ptr> c = {new int{1}, new int{2}};
// error - std::unique_ptr is non-copyable

C-tor with std::initializer_list has greater priority, even if other c-tors match.


Exercise

Use initializer_list to initialize the collection.

Add a new constructor to Shape - Shape(Color c). What happens?

Use constructor inheritance to allow initialization of all shapes providing only a Color as a parameter.

Create some shapes providing a Color only param.

Add in-class field initialization for all shapes to safely use inherited constructor.