1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
|
# c++
openstd [cpp standards][openstd-stds].
Source files of most examples is available [here][src-examples].
## Type deduction
Force compile error to see what `auto` is deduced to.
```cpp
auto foo = bar();
// force compile error
typename decltype(foo)::_;
```
## Strict aliasing and type punning
The `strict aliasing` rules describe via which `alias` a value can be accessed.
> Informal: an `alias` is a reference / pointer to a value.
Accessing a value through an alias that violates the strict aliasing rules is
`undefined behavior (UB)`.
Examples below on [godbolt](https://godbolt.org/z/TsvTY9zfj).
```cpp
int i = 0;
// Valid aliasing (signed / unsigned type).
*reinterpret_cast<signed int*>(&i);
*reinterpret_cast<unsigned int*>(&i);
// Valid aliasing (cv qualified type).
*reinterpret_cast<const int*>(&i);
*reinterpret_cast<const unsigned*>(&i);
// Valid aliasing (byte type).
*reinterpret_cast<char*>(&i);
*reinterpret_cast<std::byte*>(&i);
// Invalid aliasing, dereferencing pointer is UB.
*reinterpret_cast<short*>(&i);
*reinterpret_cast<float*>(&i);
```
> NOTE: Casting pointer to invalid aliasing type is not directly UB, but
> dereferencing the pointer is UB.
```cpp
short s[2] = { 1, 2 };
// Invalid aliasing (UB) - type punning, UB to deref ptr (int has stricter
// alignment requirements than short).
*reinterpret_cast<int*>(s);
// Arbitrary byte pointer.
char c[4] = { 1, 2, 3, 4 };
// Invalid aliasing (UB) - type punning, UB to deref ptr (int has stricter
// alignment requirements than char).
*reinterpret_cast<int*>(c);
```
At the time of writing, the current [c++ std draft][std-draft-aliasing]
contains the following.
```text
If a program attempts to access the stored value of an object through a glvalue
whose type is not **similar** (7.3.6) to one of the following types the
behavior is undefined [44]
(11.1) the dynamic type of the object,
(11.2) a type that is the signed or unsigned type corresponding to the dynamic
type of the object, or
(11.3) a char, unsigned char, or std::byte type.
[44]: The intent of this list is to specify those circumstances in which an
object can or cannot be aliased.
```
The paragraph is short but one also needs to understand the meaning of
[similar (*similar_types*)][std-draft-similar-types].
This paragraph is actually somewhat more explicit in the [c++17 std][std-17].
```text
If a program attempts to access the stored value of an object through a glvalue
of other than one of the following types the behavior is undefined [63]
(11.1) the dynamic type of the object,
(11.2) a cv-qualified version of the dynamic type of the object,
(11.3) a type similar (as defined in 7.5) to the dynamic type of the object,
(11.4) a type that is the signed or unsigned type corresponding to the dynamic
type of the object,
(11.5) a type that is the signed or unsigned type corresponding to a
cv-qualified version of the dynamic type of the object,
(11.6) an aggregate or union type that includes one of the aforementioned types
among its elements or non- static data members (including, recursively,
an element or non-static data member of a subaggregate or contained
union),
(11.7) a type that is a (possibly cv-qualified) base class type of the dynamic
type of the object,
(11.8) a char, unsigned char, or std::byte type.
[63]: The intent of this list is to specify those circumstances in which an
object may or may not be aliased.
```
Additional references:
- [What is the Strict Aliasing Rule and Why do we care][gist-strict-aliasing]
The article shows a small example how the compiler may optimized using the
strict aliasing rules.
```cpp
int alias(int* i, char* c) {
*i = 1;
*c = 'a'; // char* may alias int*
return *i;
}
int noalias(int* i, short* s) {
*i = 1;
*s = 2; // short* does not alias int*
return *i;
}
```
```x86asm
alias(int*, char*):
mov DWORD PTR [rdi] ,0x1 ; *i = 1;
mov BYTE PTR [rsi], 0x61 ; *c = 'a';
mov eax,DWORD PTR [rdi] ; Must reload, char* can alias int*.
ret
noalias(int*, short*):
mov DWORD PTR [rdi], 0x1 ; *i = 1;
mov WORD PTR [rsi], 0x2 ; *s = 2;
mov eax,0x1 ; Must not reload, short* can not alias int*.
ret
```
- [reinterpret_cast][reinterpret-aliasing] type aliasing
> 5) Any object pointer type `T1*` can be converted to another object pointer
> type `cv T2*`. This is exactly equivalent to `static_cast<cv
> T2*>(static_cast<cv void*>(expression))` (which implies that if T2's
> alignment requirement is not stricter than T1's, the value of the pointer
> does not change and conversion of the resulting pointer back to its
> original type yields the original value). In any case, the resulting
> pointer may only be dereferenced safely if allowed by the type aliasing
> rules (see below).
```cpp
int I;
char* X = reinterpret_cast<char*>(&I); // Valid, char allowed to alias int.
*X = 42;
int* Y = reinterpret_cast<int*>(X); // Cast back to original type.
*Y = 1337; // safe
char C[4];
int* P = reinterpret_cast<int*>(C); // Cast is ok, not yet UB.
*P = 1337; // UB, violates strict aliasing / alignment rules.
// https://stackoverflow.com/questions/52492229/c-byte-array-to-int
```
- On `gcc` strict aliasing is enabled starting with `-O2`.
```bash
for i in {0..3} g s; do echo "-O$i $(g++ -Q --help=optimizers -O$i | grep fstrict-aliasing)"; done
-O0 -fstrict-aliasing [disabled]
-O1 -fstrict-aliasing [disabled]
-O2 -fstrict-aliasing [enabled]
-O3 -fstrict-aliasing [enabled]
-Og -fstrict-aliasing [disabled]
-Os -fstrict-aliasing [enabled]
```
### `__restrict` keyword
The `__restrict` keyword allows the programmer to tell the compiler that two
pointer will not alias each other.
```cpp
int alias(int* a, int* b) {
*a = 1;
*b = 2;
return *a;
}
// alias(int*, int*): # @alias(int*, int*)
// mov dword ptr [rdi], 1
// mov dword ptr [rsi], 2
// mov eax, dword ptr [rdi]
// ret
int noalias(int* __restrict a, int* __restrict b) {
*a = 1;
*b = 2;
return *a;
}
// noalias(int*, int*): # @noalias(int*, int*)
// mov dword ptr [rdi], 1
// mov dword ptr [rsi], 2
// mov eax, 1
// ret
```
However this should only be used with care and in a narrow scope, as it is easy
to violate self defined contract, see [godbolt](https://godbolt.org/z/e8x1af3Mh).
### Type punning
The correct way to do `type-punning` in c++:
1. [`std::bit_cast`][std-bitcast] (c++20)
1. [`std::memcpy`](https://godbolt.org/z/3PM4jGvEz)
## Variadic templates ([parameter pack][parameter-pack])
```cpp
{{#include c++/meta.cc:3:}}
```
## Forwarding reference ([fwd ref][fwd-ref])
A `forwarding reference` is a special references that preserves the `value
category` of a function parameter and therefore allows for `perfect`
forwarding.
A forwarding reference is a parameter of a function template, which is declared
as `rvalue` reference to a `non-cv` qualified `type` template parameter.
```cpp
template<typename T>
void fn(T&& param); // param is a forwarding reference
```
Perfect forwarding can be achieved with [`std::forward`][std-fwd]. This for
example allows a wrapper function to pass a parameter with the **exact** same
value category to a down-stream function which is being invoked in the wrapper.
```cpp
{{#include c++/fwd.cc:3:}}
```
## Example: `any_of` template meta function
```cpp
{{#include c++/meta3.cc:3:}}
```
## Example: [SFINAE][sfinae] ([enable_if][enable-if])
Provide a single entry point `Invoke` to call some `Operations`.
Use `enable_if` to enable/disable the template functions depending on the two
available traits an operation can have:
- Operation returns a result
- Operation requires a context
```cpp
{{#include c++/meta2.cc:3:}}
```
## Example: Minimal templatized test registry
A small test function registry bringing together a few different template
features.
```cpp
{{#include c++/meta4.cc:3:}}
```
## Example: Concepts pre c++20
Prior to c++20's concepts, `SFINAE` and `std::void_t` can be leveraged to build
something similar allowing to define an interface (aka trait) for a template
parameter.
```cpp
{{#include c++/concepts-11.cc:3:}}
```
The main mechanic can be explained with the following reduced example. If one
of the `decltype(std:declval<T>...` expressions is ill-formed, the template
specialization for `is_valid` will be removed from the candidate set due to
[SFINAE][sfinae].
```cpp
{{#include c++/tmpl-void_t.cc:3:45}}
```
> `std::declval<T>()` creates an instance of type T in an unevaluated context.
A more detailed description is available in the SO discussion [How does
`void_t` work](https://stackoverflow.com/a/27688405).
## Template selection with partially / fully specializations.
```cpp
{{#include c++/tmpl-pair.cc:3:}}
```
# Example: Perfect forwarding
```cpp
{{#include c++/fwd-perfect.cc:3:}}
```
[parameter-pack]: https://en.cppreference.com/w/cpp/language/parameter_pack
[enable-if]: https://en.cppreference.com/w/cpp/types/enable_if
[sfinae]: https://en.cppreference.com/w/cpp/language/sfinae
[fwd-ref]: https://en.cppreference.com/w/cpp/language/reference#Forwarding_references
[std-fwd]: https://en.cppreference.com/w/cpp/utility/forward
[std-bitcast]: https://en.cppreference.com/w/cpp/numeric/bit_cast
[src-examples]: https://github.com/johannst/notes/tree/master/src/development/c%2B%2B
[reinterpret-aliasing]: https://en.cppreference.com/w/cpp/language/reinterpret_cast#Type_aliasing
[gist-strict-aliasing]: https://gist.github.com/shafik/848ae25ee209f698763cffee272a58f8
[std-draft-aliasing]: http://eel.is/c++draft/basic.lval#11
[std-draft-similar-types]: http://eel.is/c++draft/conv.qual#def:similar_types
[std-17]: https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/n4713.pdf
[openstd-home]: https://www.open-std.org/jtc1/sc22/wg21/
[openstd-stds]: https://www.open-std.org/jtc1/sc22/wg21/docs/standards
|