Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit bd9917e

Browse files
authored
Merge pull request #104 from bernhardmgruber/expert
Small improvements to the expert chapter
2 parents 69352b8 + b3c1b45 commit bd9917e

File tree

3 files changed

+282
-214
lines changed

3 files changed

+282
-214
lines changed

‎talk/expert/perfectforwarding.tex‎

Lines changed: 161 additions & 139 deletions
Original file line numberDiff line numberDiff line change
@@ -3,224 +3,246 @@
33
%http://eli.thegreenplace.net/2014/perfect-forwarding-and-universal-references-in-c/
44
\begin{frame}[fragile]
55
\frametitlecpp[11]{The problem}
6-
Trying to write a generic wrapper function
7-
\begin{cppcode*}{}
8-
template <typename T>
9-
void wrapper(T arg) {
10-
func(arg);
11-
}
12-
\end{cppcode*}
6+
How to write a generic wrapper function?
7+
\begin{block}{}
8+
\begin{cppcode*}{}
9+
template <typename T>
10+
void wrapper(T arg) {
11+
// code before
12+
func(arg);
13+
// code after
14+
}
15+
\end{cppcode*}
16+
\end{block}
1317
Example usage :
1418
\begin{itemize}
15-
\item emplace\_back
16-
\item make\_unique
19+
\item \mintinline{cpp}{emplace_back}
20+
\item \mintinline{cpp}{make_unique}
1721
\end{itemize}
1822
\end{frame}
1923

2024
\begin{frame}[fragile]
2125
\frametitlecpp[11]{Why is it not so simple?}
22-
\begin{cppcode*}{}
23-
template <typename T>
24-
void wrapper(T arg) {
25-
func(arg);
26-
}
27-
\end{cppcode*}
26+
\begin{block}{}
27+
\begin{cppcode*}{}
28+
template <typename T>
29+
void wrapper(T arg) {
30+
func(arg);
31+
}
32+
\end{cppcode*}
33+
\end{block}
2834
\begin{alertblock}{What about references ?}
2935
what if func takes references to avoid copies ?\\
3036
wrapper would force a copy and we fail to use references
3137
\end{alertblock}
3238
\end{frame}
3339

3440
\begin{frame}[fragile]
35-
\frametitlecpp[11]{Second try, second failure?}
36-
\begin{cppcode*}{}
37-
template <typename T>
38-
void wrapper(T &arg) {
39-
func(arg);
40-
}
41-
wrapper(42);
42-
// invalid initialization of
43-
// non-const reference from
44-
// an rvalue
45-
\end{cppcode*}
41+
\frametitlecpp[11]{Second try, second failure ?}
42+
\begin{block}{}
43+
\begin{cppcode*}{}
44+
template <typename T>
45+
void wrapper(T& arg) {
46+
func(arg);
47+
}
48+
wrapper(42);
49+
// invalid initialization of
50+
// non-const reference from
51+
// an rvalue
52+
\end{cppcode*}
53+
\end{block}
4654
\begin{alertblock}{}
47-
const ref won't help : you may want to pass something non const\\
48-
and rvalue are not yet supported...
55+
\begin{itemize}
56+
\item \mintinline{cpp}{const T&} won't work when passing something non const
57+
\item rvalues are not supported in either case
58+
\end{itemize}
4959
\end{alertblock}
5060
\end{frame}
5161

5262
\begin{frame}[fragile]
5363
\frametitlecpp[11]{The solution: cover all cases}
54-
\begin{cppcode*}{}
55-
template <typename T>
56-
void wrapper(T& arg) { func(arg); }
64+
\begin{block}{}
65+
\begin{cppcode*}{}
66+
template <typename T>
67+
void wrapper(T& arg) { func(arg); }
5768

58-
template <typename T>
59-
void wrapper(const T& arg) { func(arg); }
69+
template <typename T>
70+
void wrapper(const T& arg) { func(arg); }
6071

61-
template <typename T>
62-
void wrapper(T&& arg) { func(arg); }
63-
\end{cppcode*}
72+
template <typename T>
73+
void wrapper(T&& arg) { func(arg); }
74+
\end{cppcode*}
75+
\end{block}{}
6476
\end{frame}
6577

6678
\begin{frame}[fragile]
6779
\frametitlecpp[11]{The new problem: scaling to n arguments}
68-
\begin{cppcode*}{}
69-
template <typename T1, typename T2>
70-
void wrapper(T1& arg1, T2& arg2)
71-
{ func(arg1, arg2); }
72-
73-
template <typename T1, typename T2>
74-
void wrapper(const T1& arg1, T2& arg2)
75-
{ func(arg1, arg2); }
76-
77-
template <typename T1, typename T2>
78-
void wrapper(T1& arg1, const T2& arg2)
79-
{ func(arg1, arg2); }
80-
...
81-
\end{cppcode*}
80+
\begin{block}{}
81+
\begin{cppcode*}{}
82+
template <typename T1, typename T2>
83+
void wrapper(T1& arg1, T2& arg2)
84+
{ func(arg1, arg2); }
85+
86+
template <typename T1, typename T2>
87+
void wrapper(const T1& arg1, T2& arg2)
88+
{ func(arg1, arg2); }
89+
90+
template <typename T1, typename T2>
91+
void wrapper(T1& arg1, const T2& arg2)
92+
{ func(arg1, arg2); }
93+
...
94+
\end{cppcode*}
95+
\end{block}{}
8296
\begin{alertblock}{Exploding complexity}
8397
3$^{n}$ complexity\\
8498
you do not want to try n = 5...
8599
\end{alertblock}
86100
\end{frame}
87101

88102
\begin{frame}[fragile]
89-
\frametitlecpp[11]{Reference collapsing in \cpp98}
103+
\frametitlecpp[11]{Reference collapsing}
90104
\begin{block}{Reference to references}
91-
They are forbidden in \cpp\\
92-
But still may happen
105+
\begin{itemize}
106+
\item They are forbidden, but some compilers allow them
107+
\end{itemize}
108+
\end{block}
109+
\begin{block}{}
93110
\begin{cppcode*}{}
94111
template <typename T>
95-
void foo(T t) {
96-
T& k = t;
97-
...
98-
}
112+
void foo(T t) { T& k = t; } // int& &
99113
int ii = 4;
100114
foo<int&>(ii);
101115
\end{cppcode*}
102116
\end{block}
103-
\begin{exampleblock}{Practically}
104-
all compilers were collapsing the 2 references
105-
\end{exampleblock}
106-
\end{frame}
107-
108-
\begin{frame}
109-
\frametitlecpp[11]{Reference collapsing in \cpp11}
110-
\begin{block}{rvalues have been added}
117+
\begin{block}{\cpp11 added rvalues}
111118
\begin{itemize}
112-
\item what about int\&\&\&?
113-
\item and int \&\&\&\&?
119+
\item what about \mintinline{cpp}{int&& &} ?
120+
\item and int \mintinline{cpp}{&& &&} ?
114121
\end{itemize}
115122
\end{block}
116-
\begin{exampleblock}{\cpp11 standardization}
117-
The rule is simple : \& always wins\\
118-
\&\&\&, \&\&\&, \&\& $\rightarrow$ \&\\
119-
\&\&\&\& $\rightarrow$ \&\&
123+
\begin{exampleblock}{Rule}
124+
\mintinline{cpp}{&} always wins\\
125+
\mintinline{cpp}{&& &, & &&, & &} $\rightarrow$ \mintinline{cpp}{&}\\
126+
\mintinline{cpp}{&& &&} $\rightarrow$ \mintinline{cpp}{&&}
120127
\end{exampleblock}
121128
\end{frame}
122129

123130
\begin{frame}[fragile]
124131
\frametitlecpp[11]{rvalue in type-deducing context}
125-
\begin{cppcode*}{}
126-
template <typename T>
127-
void func(T&& t) {}
128-
\end{cppcode*}
129-
Next to a template parameter, \&\& is not an rvalue, but a ``universal reference''\\
130-
T\&\& actual type depends on the arguments passed to func
132+
\begin{block}{}
133+
\begin{cppcode*}{}
134+
template <typename T>
135+
void func(T&& t) {}
136+
\end{cppcode*}
137+
\end{block}
138+
Next to a template parameter, \mintinline{cpp}{&&} is not an rvalue, but a ``forwarding reference'' (aka. ``universal reference'')\\
139+
\mintinline{cpp}{T&&} actual type depends on the arguments passed to func
131140
\begin{itemize}
132-
\item if an lvalue of type U is given, T is deduced to U\&
141+
\item if an lvalue of type U is given, T is deduced to \mintinline{cpp}{U&}
133142
\item otherwise, collapse references normally
134143
\end{itemize}
135-
\begin{cppcode*}{firstnumber=3}
136-
func(4); // rvalue -> T&& is int&&
137-
double d = 3.14;
138-
func(d); // lvalue -> T&& is double&
139-
float f() {...}
140-
func(f()); // rvalue -> T&& is float&&
141-
int foo(int i) {
142-
func(i); // lvalue -> T&& is int&
143-
}
144-
\end{cppcode*}
144+
\begin{block}{}
145+
\begin{cppcode*}{firstnumber=3}
146+
func(4); // rvalue -> T&& is int&&
147+
double d = 3.14;
148+
func(d); // lvalue -> T&& is double&
149+
float f() {...}
150+
func(f()); // rvalue -> T&& is float&&
151+
int foo(int i) {
152+
func(i); // lvalue -> T&& is int&
153+
}
154+
\end{cppcode*}
155+
\end{block}
145156
\end{frame}
146157

147158
\begin{frame}[fragile]
148159
\frametitlecpp[11]{std::remove\_reference}
149-
Some template trickery removing reference from a type
150-
\begin{cppcode*}{}
151-
template< typename T >
152-
struct remove_reference
153-
{using type = T;};
154-
155-
template< typename T >
156-
struct remove_reference<T&>
157-
{using type = T;};
158-
159-
template< typename T >
160-
struct remove_reference<T&&>
161-
{using type = T;};
162-
\end{cppcode*}
163-
If {\ttfamily T} is a reference type, {\ttfamily remove\_reference<T>::type} is the type referred to by T,
164-
otherwise it is T.
160+
Type trait to remove reference from a type
161+
\begin{block}{}
162+
\begin{cppcode*}{}
163+
template <typename T>
164+
struct remove_reference { using type = T; };
165+
166+
template <typename T>
167+
struct remove_reference<T&> { using type = T; };
168+
169+
template <typename T>
170+
struct remove_reference<T&&> { using type = T; };
171+
\end{cppcode*}
172+
\end{block}
173+
If {\ttfamily T} is a reference type, \mintinline{cpp}{remove_reference_t<T>::type} is the type referred to by {\ttfamily T},
174+
otherwise it is {\ttfamily T}.
165175
\end{frame}
166176

167177
\begin{frame}[fragile]
168178
\frametitlecpp[11]{std::forward}
169-
Another template trickery keeping references and mapping non reference types to rvalue references
170-
\begin{cppcode*}{}
171-
template<typename T>
172-
T&& forward(typename std::remove_reference<T>::type& t)
173-
noexcept {
174-
return static_cast<T&&>(t);
175-
}
176-
\end{cppcode*}
179+
Keeps references and maps non-reference types to rvalue references
180+
\begin{block}{}
181+
\small
182+
\begin{cppcode*}{}
183+
template<typename T>
184+
T&& forward(typename std::remove_reference<T>
185+
::type& t) noexcept {
186+
return static_cast<T&&>(t);
187+
}
188+
template<typename T>
189+
T&& forward(typename std::remove_reference<T>
190+
::type&& t) noexcept {
191+
return static_cast<T&&>(t);
192+
}
193+
\end{cppcode*}
194+
\end{block}
177195
\begin{block}{How it works}
178196
\begin{itemize}
179-
\item if T is int, it returns int \&\&
180-
\item if T is int\&, it returns int\&\&\& ie int\&
181-
\item if T is int\&\&, it returns int\&\&\&\& ie int\&\&
197+
\item if T is \mintinline{cpp}{int}, it returns \mintinline{cpp}{int&&}
198+
\item if T is \mintinline{cpp}{int&}, it returns \mintinline{cpp}{int& &&} ie. \mintinline{cpp}{int&}
199+
\item if T is \mintinline{cpp}{int&&}, it returns \mintinline{cpp}{int&& &&} ie. \mintinline{cpp}{int&&}
182200
\end{itemize}
183201
\end{block}
184202
\end{frame}
185203

186204
\begin{frame}[fragile]
187205
\frametitlecpp[11]{Perfect forwarding}
188206
Putting it all together
189-
\begin{cppcode*}{}
190-
template <typename... T>
191-
void wrapper(T&&... args) {
192-
func(std::forward<T>(args)...);
193-
}
194-
\end{cppcode*}
195-
\begin{block}{How it works}
207+
\begin{block}{}
208+
\begin{cppcode*}{}
209+
template <typename... T>
210+
void wrapper(T&&... args) {
211+
func(std::forward<T>(args)...);
212+
}
213+
\end{cppcode*}
214+
\end{block}
215+
\begin{block}{}
196216
\begin{itemize}
197-
\item if we pass an rvalue to wrapper (U\&\&)
217+
\item if we pass an rvalue to wrapper (\mintinline{cpp}{U&&})
198218
\begin{itemize}
199-
\item arg will be of type U\&\&
200-
\item func will be called with a U\&\&
219+
\item arg will be of type \mintinline{cpp}{U&&}
220+
\item func will be called with a \mintinline{cpp}{U&&}
201221
\end{itemize}
202-
\item if we pass an lvalue to wrapper (U\&)
222+
\item if we pass an lvalue to wrapper (\mintinline{cpp}{U&})
203223
\begin{itemize}
204-
\item arg will be of type U\&
205-
\item func will be called with a U\&
224+
\item arg will be of type \mintinline{cpp}{U&}
225+
\item func will be called with a \mintinline{cpp}{U&}
206226
\end{itemize}
207-
\item if we pass a plain value (U)
227+
\item if we pass a plain value (\mintinline{cpp}{U})
208228
\begin{itemize}
209-
\item arg will be of type U\&\& (no copy in wrapper)
210-
\item func will be called with a U\&\&
211-
\item but func takes a U, so copy happens there, as expected
229+
\item arg will be of type \mintinline{cpp}{U&&} (no copy in wrapper)
230+
\item func will be called with a \mintinline{cpp}{U&&}
231+
\item but func takes a \mintinline{cpp}{U&}, so copy happens there, as expected
212232
\end{itemize}
213233
\end{itemize}
214234
\end{block}
215235
\end{frame}
216236

217237
\begin{frame}[fragile]
218238
\frametitlecpp[11]{Real life example}
219-
\begin{cppcode*}{}
220-
template<typename T, typename... Args>
221-
unique_ptr<T> make_unique(Args&&... args) {
222-
return unique_ptr<T>
223-
(new T(std::forward<Args>(args)...));
224-
}
225-
\end{cppcode*}
239+
\begin{block}{}
240+
\begin{cppcode*}{}
241+
template<typename T, typename... Args>
242+
unique_ptr<T> make_unique(Args&&... args) {
243+
return unique_ptr<T>
244+
(new T(std::forward<Args>(args)...));
245+
}
246+
\end{cppcode*}
247+
\end{block}
226248
\end{frame}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /