358 lines
No EOL
14 KiB
Markdown
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<double> c(4.0, 2.0); <span class="fragment">// initialization of classes </span>
|
|
|
|
std::vector<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<double> c{4.0, 2.0}; <span class="fragment">// brace initialization calls adequate c-tor</span>
|
|
|
|
std::vector<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<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} {}
|
|
};
|
|
|
|
<span class="fragment">Bar<int> c = {1, 2, 5, 51};</span> <span class="fragment">// calls std::initializer_list c-tor</span>
|
|
<span class="fragment">Bar<int> d{1, 2, 5, 51};</span> <span class="fragment">// calls std::initializer_list c-tor</span>
|
|
<span class="fragment">Bar<int> e = {1, 2};</span> <span class="fragment">// calls std::initializer_list c-tor</span>
|
|
<span class="fragment">Bar<int> f{1, 2};</span> <span class="fragment">// calls std::initializer_list c-tor</span>
|
|
<span class="fragment">Bar<int> g(1, 2);</span> <span class="fragment"> // calls Bar(Type a, Type b) c-tor </span>
|
|
<span class="fragment">Bar<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<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
|
|
``` |