You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
@@ -469,6 +469,52 @@ If a constructor throws an exception, the order of destruction is the reverse of
469
469
470
470
1. If the constructor is non-delegating, all fully-constructed base class objects and members are destroyed. However, because the object itself is not fully constructed, the destructor is not run.
471
471
472
+
## <a name="extended_aggregate"></a> Derived constructors and extended aggregate initialization
473
+
474
+
If the constructor of a base class is non-public, but accessible to a derived class, then under **/std:c++17** mode in Visual Studio 2017 and later you can't use empty braces to initialize an object of the derived type.
475
+
476
+
The following example shows C++14 conformant behavior:
477
+
478
+
```cpp
479
+
struct Derived;
480
+
481
+
struct Base {
482
+
friend struct Derived;
483
+
private:
484
+
Base() {}
485
+
};
486
+
487
+
struct Derived : Base {};
488
+
489
+
Derived d1; // OK. No aggregate init involved.
490
+
Derived d2 {}; // OK in C++14: Calls Derived::Derived()
491
+
// which can call Base ctor.
492
+
```
493
+
494
+
In C++17, `Derived` is now considered an aggregate type. It means that the initialization of `Base` via the private default constructor happens directly, as part of the extended aggregate initialization rule. Previously, the `Base` private constructor was called via the `Derived` constructor, and it succeeded because of the friend declaration.
495
+
496
+
The following example shows C++17 behavior in Visual Studio 2017 and later in **/std:c++17** mode:
### Constructors for classes that have multiple inheritance
473
519
474
520
If a class is derived from multiple base classes, the base class constructors are invoked in the order in which they are listed in the declaration of the derived class:
Copy file name to clipboardExpand all lines: docs/cpp/initializing-classes-and-structs-without-constructors-cpp.md
+2Lines changed: 2 additions & 0 deletions
Original file line number
Diff line number
Diff line change
@@ -131,6 +131,8 @@ kr->add_d({ 4.5 });
131
131
return { 4.5 };
132
132
```
133
133
134
+
In **/std:c++17** mode, the rules for empty brace initialization are slightly more restrictive. See [Derived constructors and extended aggregate initialization](constructors-cpp.md#extended_aggregate).
135
+
134
136
## initializer_list constructors
135
137
136
138
The [initializer_list Class](../standard-library/initializer-list-class.md) represents a list of objects of a specified type that can be used in a constructor, and in other contexts. You can construct an initializer_list by using brace initialization:
Any built-in or user-defined type can be used as a type argument. For example, you can use std::vector in the Standard Library to store ints, doubles, strings, MyClass, constMyClass*, MyClass&. The primary restriction when using templates is that a type argument must support any operations that are applied to the type parameters. For example, if we call minimum using MyClass as in this example:
77
+
Any built-in or user-defined type can be used as a type argument. For example, you can use [std::vector](../standard-library/vector-class.md) in the Standard Library to store variables of type **int**, **double**, [std::string](../standard-library/basic-string-class.md), `MyClass`, **const**`MyClass`*, `MyClass&`, and so on. The primary restriction when using templates is that a type argument must support any operations that are applied to the type parameters. For example, if we call `minimum` using `MyClass` as in this example:
78
78
79
79
```cpp
80
80
classMyClass
@@ -92,7 +92,7 @@ int main()
92
92
}
93
93
```
94
94
95
-
A compiler error will be generated because MyClass does not provide an overload for the < operator.
95
+
A compiler error will be generated because `MyClass` does not provide an overload for the **<** operator.
96
96
97
97
There is no inherent requirement that the type arguments for any particular template all belong to the same object hierarchy, although you can define a template that enforces such a restriction. You can combine object-oriented techniques with templates; for example, you can store a Derived* in a vector\<Base\*>. Note that the arguments must be pointers
98
98
@@ -106,11 +106,11 @@ vector<MyClass*> vec;
106
106
vec2.push_back(make_shared<MyDerived>());
107
107
```
108
108
109
-
The basic requirements that vector and other standard library containers impose on elements of `T` is that `T` be copy-assignable and copy-constructible.
109
+
The basic requirements that `std::vector` and other standard library containers impose on elements of `T` is that `T` be copy-assignable and copy-constructible.
110
110
111
111
## Non-type parameters
112
112
113
-
Unlike generic types in other languages such as C# and Java, C++ templates support non-type parameters, also called value parameters. For example, you can provide a constant integral value to specify the length of an array, as with this example that is similar to the std::array class in the Standard Library:
113
+
Unlike generic types in other languages such as C# and Java, C++ templates support *non-type parameters*, also called value parameters. For example, you can provide a constant integral value to specify the length of an array, as with this example that is similar to the [std::array](../standard-library/array-class-stl.md) class in the Standard Library:
114
114
115
115
```cpp
116
116
template<typename T, size_t L>
@@ -122,14 +122,26 @@ public:
122
122
};
123
123
```
124
124
125
-
Note the syntax in the template declaration. The size_t value is passed in as a template argument at compile time and must be constant or a constexpr expression. You use it like this:
125
+
Note the syntax in the template declaration. The `size_t` value is passed in as a template argument at compile time and must be **const** or a **constexpr** expression. You use it like this:
126
126
127
127
```cpp
128
128
MyArray<MyClass*, 10> arr;
129
129
```
130
130
131
131
Other kinds of values including pointers and references can be passed in as non-type parameters. For example, you can pass in a pointer to a function or function object to customize some operation inside the template code.
132
132
133
+
### Type deduction for non-type template parameters
134
+
135
+
In Visual Studio 2017 and later, in **/std:c++17** mode the compiler deduces the type of a non-type template argument that is declared with **auto**:
136
+
137
+
```cpp
138
+
template <auto x> constexprauto constant = x;
139
+
140
+
auto v1 = constant<5>; // v1 == 5, decltype(v1) is int
141
+
auto v2 = constant<true>; // v2 == true, decltype(v2) is bool
142
+
auto v3 = constant<'a'>; // v3 == 'a', decltype(v3) is char
143
+
```
144
+
133
145
## <aid="template_parameters"></a> Templates as template parameters
134
146
135
147
A template can be a template parameter. In this example, MyClass2 has two template parameters: a typename parameter *T* and a template parameter *Arr*:
If the constructor of a base class is non-public, but accessible to a derived class, then under **/std:c++17** mode in Visual Studio version 15.7 you can no longer use empty braces to initialize an object of the derived type.
1239
-
1238
+
If the constructor of a base class is non-public, but accessible to a derived class, then under **/std:c++17** mode in Visual Studio 2017 version 15.7 you can no longer use empty braces to initialize an object of the derived type.
1240
1239
The following example shows C++14 conformant behavior:
1241
1240
1242
1241
```cpp
1243
1242
struct Derived;
1244
-
1245
1243
struct Base {
1246
1244
friend struct Derived;
1247
1245
private:
1248
1246
Base() {}
1249
1247
};
1250
1248
1251
1249
struct Derived : Base {};
1252
-
1253
1250
Derived d1; // OK. No aggregate init involved.
1254
1251
Derived d2 {}; // OK in C++14: Calls Derived::Derived()
1255
1252
// which can call Base ctor.
1256
1253
```
1257
1254
1258
1255
In C++17, `Derived` is now considered an aggregate type. It means that the initialization of `Base` via the private default constructor happens directly, as part of the extended aggregate initialization rule. Previously, the `Base` private constructor was called via the `Derived` constructor, and it succeeded because of the friend declaration.
1259
-
1260
1256
The following example shows C++17 behavior in Visual Studio version 15.7 in **/std:c++17** mode:
0 commit comments