trainings/AdvancedCppV2/Presentation/moder_cpp_cpp11.md

358 lines
No EOL
14 KiB
Markdown

## Cpp11
<!-- .slide: data-background="#ccc" -->
* <!-- .element: class="fragment fade-in" --> A quick reminder of lesser known features
* <!-- .element: class="fragment fade-in" --> static_assert
* <!-- .element: class="fragment fade-in" --> Uniform initialization
* <!-- .element: class="fragment fade-in" --> In-class initialization of non-static variables
* <!-- .element: class="fragment fade-in" --> initializer_list
* <!-- .element: class="fragment fade-in" --> alias
* <!-- .element: class="fragment fade-in" --> Template alias
* <!-- .element: class="fragment fade-in" --> C'tor inheritance
* <!-- .element: class="fragment fade-in" --> Attributes
* <!-- .element: class="fragment fade-in" --> Data structure alignment
___
<!-- .slide: data-background="#ccc" --><!-- .slide: data-background="#ccc" -->
## static_assert
```cpp
template <class T>
void swap(T& a, T& b)
{
static_assert(std::is_copy_constructible<T>::value,
"Swap requires copying");
static_assert(std::is_nothrow_move_constructible_v<T> &&
std::is_nothrow_move_assignable_v<T>);
auto c = b;
b = a;
a = c;
}
```
<!-- .element: class="fragment fade-in" -->
**Rationale**: Preventing compilation on user defined conditions (usually specific types).
<!-- .element: class="fragment fade-in" -->
Performs compile-time assertion checking. Usually used with `<type_traits>` library.
<!-- .element: class="fragment fade-in" -->
The message is optional from C++17.
<!-- .element: class="fragment fade-in" -->
<!-- .slide: style="font-size: 0.9em" -->
___
<!-- .slide: data-background="#ccc" --><!-- .slide: data-background="#ccc" -->
## C++98/03 initialization
<pre><code class="cpp" data-trim data-line-numbers data-noescape>
int a; <span class="fragment">// undefined value </span>
int b(5); <span class="fragment">// direct initialization, b = 5 </span>
int c = 10; <span class="fragment">// copy initialization, c = 10 </span>
int d = int(); <span class="fragment">// default initialization, d = 0 </span>
int e(); <span class="fragment">// function declaration - "most vexing parse"</span>
int values[] = { 1, 2, 3, 4 }; <span class="fragment">// brace initialization of aggregate </span>
int array[] = { 1, 2, 3.5 }; <span class="fragment">// C++98 - ok, implicit type narrowing </span>
struct P { int a, b; }; <span> </span>
P p = { 20, 40 }; <span class="fragment">// brace initialization of POD </span>
std::complex&lt;double> c(4.0, 2.0); <span class="fragment">// initialization of classes </span>
std::vector&lt;std::string> names; <span class="fragment">// no initialization for list of values </span>
names.push_back("John"); <span> </span>
names.push_back("Jane"); <span> </span>
</code></pre>
<!-- .slide: style="font-size: 0.93em" -->
___
<!-- .slide: data-background="#ccc" --><!-- .slide: data-background="#ccc" -->
## C++11 initialization with {}
<pre><code class="cpp" data-trim data-line-numbers data-noescape>
int a; <span class="fragment">// still undefined value </span>
int b{5}; <span class="fragment">// brace initialization, b = 5 </span>
int c{}; <span class="fragment">// brace initialization, c = 0 </span>
int values[] = { 1, 2, 3, 4 }; <span class="fragment">// brace initialization of aggregate </span>
int array[] = { 1, 2, 3.5 }; <span class="fragment">// C++11: error - implicit type narrowing </span>
struct P { int a, b;<span> </span>
P p = { 20, 40 }; <span class="fragment">// brace initialization of POD </span>
std::complex&lt;double> c{4.0, 2.0}; <span class="fragment">// brace initialization calls adequate c-tor</span>
std::vector&lt;std::string> names = { "John", "Jane" }; <span> </span>
<span class="fragment">// brace initialization of vector </span>
</code></pre>
**Rationale**: eliminate problematic initialization cases from C++98, initialization of STL containers, have one universal way of initialization.
<!-- .element: class="fragment fade-in" -->
<!-- .slide: style="font-size: 0.90em" -->
___
<!-- .slide: data-background="#ccc" --><!-- .slide: data-background="#ccc" -->
## In-class initialization of non-static variables
```cpp
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
```
___
<!-- .slide: data-background="#ccc" --><!-- .slide: data-background="#ccc" -->
## `std::initializer_list<T>`
```cpp
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>
```
* <!-- .element: class="fragment fade-in" --> Defined in <code>initializer_list</code> header
* <!-- .element: class="fragment fade-in" --> Elements are kept in an array
* <!-- .element: class="fragment fade-in" --> Elements are immutable
* <!-- .element: class="fragment fade-in" --> Elements must be copyable
* <!-- .element: class="fragment fade-in" --> Have limited interface and access via iterators - <code>begin()</code>, <code>end()</code>, <code>size()</code>
* <!-- .element: class="fragment fade-in" --> Should be passed to functions by value
___
<!-- .slide: data-background="#ccc" --><!-- .slide: data-background="#ccc" -->
## Constructor priority
<pre><code class="cpp" data-trim data-line-numbers data-noescape>
template&lt;class Type>
class Bar {
std::vector&lt;Type> values_;
public:
Bar(std::initializer_list&lt;Type> values) : values_(values) {}
Bar(Type a, Type b) : values_{a, b} {}
};
<span class="fragment">Bar&lt;int> c = {1, 2, 5, 51};</span> <span class="fragment">// calls std::initializer_list c-tor</span>
<span class="fragment">Bar&lt;int> d{1, 2, 5, 51};</span> <span class="fragment">// calls std::initializer_list c-tor</span>
<span class="fragment">Bar&lt;int> e = {1, 2};</span> <span class="fragment">// calls std::initializer_list c-tor</span>
<span class="fragment">Bar&lt;int> f{1, 2};</span> <span class="fragment">// calls std::initializer_list c-tor</span>
<span class="fragment">Bar&lt;int> g(1, 2);</span> <span class="fragment"> // calls Bar(Type a, Type b) c-tor </span>
<span class="fragment">Bar&lt;int> h = {};</span> <span class="fragment">// calls std::initializer_list c-tor</span>
<span class="fragment"> // or default c-tor if exists</span>
<span class="fragment">Bar&lt;std::unique_ptr<int>> c = {new int{1}, new int{2}}; </span>
<span class="fragment">// error - std::unique_ptr is non-copyable </span>
</code></pre>
C-tor with <code>std::initializer_list</code> has greater priority, even if other c-tors match.
<!-- .element: class="fragment fade-in" -->
___
<!-- .slide: data-background="#ccc" --><!-- .slide: data-background="#ccc" -->
## Exercise 1
* <!-- .element: class="fragment fade-in" --> Open project streamer
* <!-- .element: class="fragment fade-in" --> Add two C'tor:
* <!-- .element: class="fragment fade-in" --> first will take <code>initializer_list</code>
* <!-- .element: class="fragment fade-in" --> second <code>const StreamInfo&</code>
* <!-- .element: class="fragment fade-in" --> initialize <code>vector</code> in <code><b>initialization</b> list</code>
___
<!-- .slide: data-background="#ccc" --><!-- .slide: data-background="#ccc" -->
## Type aliasing
```cpp
typedef std::ios_base::fmtflags Flags;
using Flags = std::ios_base::fmtflags; // the same as above
Flags fl = std::ios_base::dec;
```
<!-- .element: class="fragment fade-in" -->
```cpp
typedef std::vector<std::shared_ptr<Socket>> SocketContainer;
std::vector<std::shared_ptr<Socket>> typedef SocketContainer; // correct ;)
using SocketContainer = std::vector<std::shared_ptr<Socket>>;
```
<!-- .element: class="fragment fade-in" -->
**Rationale**: More intuitive alias creation.
<!-- .element: class="fragment fade-in" -->
A type alias is a name that refers to a previously defined type. It could be created with typedef.
From C++11 type aliases should be created with `using` keyword.
<!-- .element: class="fragment fade-in" -->
___
<!-- .slide: data-background="#ccc" --><!-- .slide: data-background="#ccc" -->
### Template aliases
```cpp
struct ThemedLabelToogleButton { ... }
template <typename T>
using ButtonMap = std::map<ThemedLabelToogleButton, T>;
ButtonMap<std::function<void()>> my_map;
// std::map<ThemedLabelToogleButton, std::function<void()>
```
Type alias can be parametrized with templates. It was impossible with typedef.
<!-- .element: class="fragment fade-in" -->
Template aliases cannot be specialized.
<!-- .element: class="fragment fade-in" -->
___
<!-- .slide: data-background="#ccc" --><!-- .slide: data-background="#ccc" -->
### Constructors inheritance
```cpp
struct A {
explicit A(int);
int a;
};
struct B : A {
using A::A; // implicit declaration of B::B(int)
B(int, int); // overloaded inherited Base ctor
};
```
* <!-- .element: class="fragment fade-in" --> Derived class constructors are generated implicitly, only if they are used
* <!-- .element: class="fragment fade-in" --> Derived class constructors take the same arguments as base class constructors
* <!-- .element: class="fragment fade-in" --> Derived class constructor calls according base class constructor
* <!-- .element: class="fragment fade-in" --> Constructor inheritance in a class that adds a new field might be risky - new fields can be uninitialized
___
<!-- .slide: data-background="#ccc" --><!-- .slide: data-background="#ccc" -->
## Exercise 2
* <!-- .element: class="fragment fade-in" --> Open project streamer
* <!-- .element: class="fragment fade-in" --> Add aliases for ip adress, port and vlan.
___
<!-- .slide: data-background="#ccc" --><!-- .slide: data-background="#ccc" -->
## Attributes
<!-- .slide: data-background="#ccc" -->
___
<!-- .slide: data-background="#ccc" --><!-- .slide: data-background="#ccc" -->
### Standard attributes
* <!-- .element: class="fragment fade-in" --> <code>[[noreturn]]</code> - function does never return, like <code>std::terminate</code>. If it does, we have UB
* <!-- .element: class="fragment fade-in" --> <code>[[deprecated]]</code> (C++14) - function is deprecated
* <!-- .element: class="fragment fade-in" --> <code>[[deprecated("reason")]]</code> (C++14) - as above, but compiler will emit the reason
* <!-- .element: class="fragment fade-in" --> <code>[[fallthrough]]</code> (C++17) - in <code>switch</code> statement, indicated that fall through is intentional
* <!-- .element: class="fragment fade-in" --> <code>[[nodiscard]]</code> (C++17) - you cannot ignore value returned from function
* <!-- .element: class="fragment fade-in" --> <code>[[maybe_unused]]</code> (C++17) - suppress compiler warning on unused class, typedef, variable, function, etc.
<!-- Problem with backticks if fadeing inplemented like this -->
___
<!-- .slide: data-background="#ccc" --><!-- .slide: data-background="#ccc" -->
## `[[noreturn]]` attribute
```c++
[[noreturn]] void f() {
throw "error";
// OK
}
[[noreturn]] void q(int i) {
if (i > 0) {
throw "positive";
}
// the behavior is undefined if called with argument <=0
}
```
___
<!-- .slide: data-background="#ccc" --><!-- .slide: data-background="#ccc" -->
## `[[deprecated]] attribute`
Attributes for namespaces and enumerators are available from C++17.
```c++
[[deprecated("Please use f2 instead")]] int f1();
enum E {
foo = 0,
bar [[deprecated]] = foo
};
E e = bar; // Emits warning
namespace [[deprecated]] old_stuff {
void legacy();
}
old_stuff::legacy(); //Emits warning
```
___
<!-- .slide: data-background="#ccc" --><!-- .slide: data-background="#ccc" -->
## `[[fallthrough]]` attribute
```c++
void f(int n){
void g(), h(), i();
switch(n) {
case 1:
case 2:
g();
[[fallthrough]];
case 3: // no warning on fallthrough
h();
case 4: // compiler may warn on fallthrough
i();
[[fallthrough]]; // illformed, not before a case label
}
}
```
___
<!-- .slide: data-background="#ccc" --><!-- .slide: data-background="#ccc" -->
## `[[nodiscard]]` attribute
```c++
struct [[nodiscard]] error_info {};
error_info process(Data*);
// ...
void passMessage() {
auto data = getData();
process(data); // compiler warning, discarding error_info
}
```
___
<!-- .slide: data-background="#ccc" --><!-- .slide: data-background="#ccc" -->
## `[[maybe_unused]]` attributes
```c++
[[maybe_unused]] void f([[maybe_unused]] bool thing1,
[[maybe_unused]] bool thing2)
{
[[maybe_unused]] bool b = thing1 && thing2;
assert (b); // in release mode, assert is compiled out, and b is unused
// no warning because it is declared [[maybe_unused]]
} // parameters thing1 and thing2 are not used, no warning
```