Skip to content

Commit dfbb1de

Browse files
committed
split solutions
1 parent 592819e commit dfbb1de

5 files changed

Lines changed: 162 additions & 160 deletions

File tree

‎exercise.pdf‎

-174 Bytes
Binary file not shown.

‎exercise/main.tex‎

Lines changed: 2 additions & 160 deletions
Original file line numberDiff line numberDiff line change
@@ -30,167 +30,9 @@
3030

3131
\begin{document}
3232

33-
\section{Recursion}
34-
Implement a lambda expression \texttt{f(int x)} that calculates $x!$ (factorial of \texttt{x}) by recursion upon calling!
35-
Use the following skeleton:
36-
\begin{lstlisting}
37-
int main() {
38-
auto f = /* TODO */
39-
return x < 2 ? x : x * f( /* TODO */
40-
});
41-
42-
return f(3);
43-
}
44-
\end{lstlisting}
45-
46-
\section{Function traits}
47-
\label{sec:fcttraits}
48-
Finish the implementation of \texttt{function\_traits} and \texttt{lambda\_traits}, such that the program compiles successfully! Note, that it is sufficient for \texttt{function\_traits} to only accept instances of \texttt{std::function}. Think about how you can use your implementation of \texttt{function\_traits} with lambda expressions and implement this logic in \texttt{lambda\_traits}. Note further, that invocations of \texttt{std::function} are not critical in terms of possible performance penalties in this scenario, as long as the traits are available at compile time (as required in \texttt{main}).
49-
50-
\inputcpplisting{snippet21a}
51-
52-
\textbf{Hint:} You may want to use \texttt{std::tuple\_element} and \texttt{std::declval}.
53-
54-
\newpage
55-
56-
\section{Passing lambdas as argument}
57-
Implement \texttt{Filters} as an logical \textit{or} filter gathering, such that the program below compiles and runs successfully.
58-
59-
\inputcpplisting{snippet20a}
60-
61-
The constructor of \texttt{Filters} should take one or more filters,
62-
\begin{lstlisting}
63-
template <typename F, typename... Fs> Filters(F f, Fs... fs)
64-
\end{lstlisting}
65-
where each filter in \texttt{fs} (and \texttt{f} itself) is a lambda (or \texttt{std::function}) that accepts an argument of type \texttt{T} and returns a boolean. \texttt{T} should be generic and is allow to be different amongst the filters.
66-
The call operator
67-
\begin{lstlisting}
68-
bool Filters::operator()(T x) const
69-
\end{lstlisting}
70-
should return the logical \textit{or} of all filters for applied \texttt{x} as shown in the example.
71-
Further, implement a function
72-
\begin{lstlisting}
73-
template <typename F> void Filters::add_filter(F)
74-
\end{lstlisting}
75-
that adds a filter to the gathering. Note, that in the example there is no common type in terms of \texttt{std::common\_type\_t} for \texttt{f1}, \texttt{f2} and \texttt{f3}:
76-
\begin{lstlisting}
77-
using T12 = std::common_type_t<decltype(f1), decltype(f2)>; // OK
78-
using T123 = std::common_type_t<T12, decltype(f3)>; // Compile-time error!
79-
\end{lstlisting}
80-
81-
If in trouble, follow the step-by-step instructions printed below!
82-
83-
\subsection{Step I}
84-
Start by finding an implementation for \texttt{Filters} that suffices the relaxed requirement
85-
\begin{lstlisting}
86-
template <typename F1, typename F2>
87-
struct Filters {
88-
Filters(F1 f1, F2 f2) {
89-
/* TODO */
90-
}
91-
92-
[[nodiscard]] auto operator()(int x) const {
93-
/* TODO */
94-
}
95-
};
96-
97-
int main() {
98-
auto f1 = [](int x) { return x % 2 == 0; };
99-
auto f2 = [](int x) { return x % 3 == 0; };
100-
Filters filters(f1, f2);
101-
return filters(5) ? 1 : 0;
102-
}
103-
\end{lstlisting}
104-
\ldots and answer the question why we need two separate template types \texttt{F1} and \texttt{F2}!
105-
106-
\subsection{Step II}
107-
Make the type of the passed argument of a filter (\texttt{int}) generic and pass it as a template parameter. You will now need to instantiate \texttt{Filters} akin to
108-
\begin{lstlisting}
109-
auto f1 = [](int x) { return x % 2 == 0; };
110-
auto f2 = [](int x) { return x % 3 == 0; };
111-
Filters<decltype(f1), decltype(f2), int> filters(f1, f2);
112-
\end{lstlisting}
113-
This is unpleasent and we will address this issue in the next step.
114-
115-
\subsection{Step III}
116-
Use a deduction guide to get rid of the explicit type naming of the filters. This is a delicate task, since we have to find the type of the argument of a passed filter. You may want to have a look at Sec.~\ref{sec:fcttraits} to find a solution for this problem.
117-
\begin{lstlisting}
118-
template <typename F1, typename F2>
119-
Filters(F1 f1, F2 f2) -> Filters<F1, F2, std::common_type_t< /* TODO */ >>
120-
\end{lstlisting}
121-
122-
\subsection{Step IV}
123-
We now generalize our solution for an arbitrary number of filters. Use variadic templates for the constructor and the deduction guide, and store the filters in a \texttt{std::vector}! Use \texttt{std::function<bool(T)>} as the value type of the vector.
124-
125-
\begin{lstlisting}
126-
template <typename T>
127-
struct Filters {
128-
std::vector<std::function<bool(T)>> filters;
129-
130-
template <typename F, typename... Fs>
131-
Filters(F f, Fs... fs): filters( /* TODO */ ) {}
132-
133-
/* TODO */
134-
};
135-
136-
template <typename... Fs>
137-
Filters(Fs... fs)
138-
-> Filters<std::common_type_t< /* TODO */ >>;
139-
\end{lstlisting}
140-
Add an sufficient implementation of
141-
\begin{lstlisting}
142-
template <typename F> void Filters::add_filter(F)
143-
\end{lstlisting}
144-
and don't forget to adopt your implementation of \texttt{Filters.operator()(T)}! (use \texttt{std::accumulate} if possible.)
145-
146-
\subsection{Step V}
147-
Can you think of an alternative to \texttt{std::function}? Why can we not use \texttt{std::common\_type} or \texttt{std::variant}?
148-
149-
\textbf{Hint:} Compare the sizes of lambdas with different captures:
150-
\begin{lstlisting}[title=\href{https://godbolt.org/z/ZBUfgY}{\texttt{godbolt.org/z/ZBUfgY}}]
151-
int capture_me = 1;
152-
std::cout << sizeof([](int x) { return x; }) << '\n';
153-
std::cout << sizeof([y=capture_me](int x) { return x + y; }) << '\n';
154-
std::cout << sizeof([y=&capture_me](int x) { return x + y; }) << '\n';
155-
\end{lstlisting}
156-
157-
\subsection{Optional}
158-
In case you are wondering what \texttt{std::common\_type} does; its rules are based on the rules for the ternary operator which can be confusing, e.g.
159-
\begin{lstlisting}[title=\href{https://godbolt.org/z/4TGmK6}{\texttt{godbolt.org/z/4TGmK6}}]
160-
struct S {};
161-
162-
template<class T, int> struct CT {
163-
operator T() const;
164-
};
165-
166-
int main() {
167-
auto a = false ? CT<int, 1>{} : CT<int, 2>{}; // OK
168-
auto b = false ? CT<int*, 1>{} : CT<int*, 2>{}; // OK
169-
auto c = false ? CT<S*, 1>{} : CT<S*, 2>{}; // OK
170-
auto d = false ? CT<S, 1>{} : CT<S, 2>{}; // Compile-time error
171-
}
172-
\end{lstlisting}
173-
Depending on what compiler you are using, the error message for \texttt{d} varies. Take a look at:
174-
\begin{itemize}
175-
\item \texttt{[over.build] \S27}
176-
\item \texttt{[expr.cond] \S6}
177-
\end{itemize}
178-
if you want to learn more.
179-
180-
\newpage
181-
182-
\section{Solutions}
183-
184-
\subsection{Recursion}
185-
\inputcpplisting{snippet35}
186-
187-
\newpage
188-
189-
\subsection{Function traits}
190-
\inputcpplisting{snippet21}
33+
\input{tasks}
19134

19235
\newpage
36+
\input{solutions}
19337

194-
\subsection{Passing lambdas as argument}
195-
\inputcpplisting{snippet20}
19638
\end{document}

‎exercise/solutions.tex‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
\section{Solutions}
2+
3+
\subsection{Recursion}
4+
\inputcpplisting{snippet35}
5+
6+
\newpage
7+
8+
\subsection{Function traits}
9+
\inputcpplisting{snippet21}
10+
11+
\newpage
12+
13+
\subsection{Passing lambdas as argument}
14+
\inputcpplisting{snippet20}

‎exercise/tasks.tex‎

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
\section{Recursion}
2+
Implement a lambda expression \texttt{f(int x)} that calculates $x!$ (factorial of \texttt{x}) by recursion upon calling!
3+
Use the following skeleton:
4+
\begin{lstlisting}
5+
int main() {
6+
auto f = /* TODO */
7+
return x < 2 ? x : x * f( /* TODO */
8+
});
9+
10+
return f(3);
11+
}
12+
\end{lstlisting}
13+
14+
\section{Function traits}
15+
\label{sec:fcttraits}
16+
Finish the implementation of \texttt{function\_traits} and \texttt{lambda\_traits}, such that the program compiles successfully! Note, that it is sufficient for \texttt{function\_traits} to only accept instances of \texttt{std::function}. Think about how you can use your implementation of \texttt{function\_traits} with lambda expressions and implement this logic in \texttt{lambda\_traits}. Note further, that invocations of \texttt{std::function} are not critical in terms of possible performance penalties in this scenario, as long as the traits are available at compile time (as required in \texttt{main}).
17+
18+
\inputcpplisting{snippet21a}
19+
20+
\textbf{Hint:} You may want to use \texttt{std::tuple\_element} and \texttt{std::declval}.
21+
22+
\newpage
23+
24+
\section{Passing lambdas as argument}
25+
Implement \texttt{Filters} as an logical \textit{or} filter gathering, such that the program below compiles and runs successfully.
26+
27+
\inputcpplisting{snippet20a}
28+
29+
The constructor of \texttt{Filters} should take one or more filters,
30+
\begin{lstlisting}
31+
template <typename F, typename... Fs> Filters(F f, Fs... fs)
32+
\end{lstlisting}
33+
where each filter in \texttt{fs} (and \texttt{f} itself) is a lambda (or \texttt{std::function}) that accepts an argument of type \texttt{T} and returns a boolean. \texttt{T} should be generic and is allow to be different amongst the filters.
34+
The call operator
35+
\begin{lstlisting}
36+
bool Filters::operator()(T x) const
37+
\end{lstlisting}
38+
should return the logical \textit{or} of all filters for applied \texttt{x} as shown in the example.
39+
Further, implement a function
40+
\begin{lstlisting}
41+
template <typename F> void Filters::add_filter(F)
42+
\end{lstlisting}
43+
that adds a filter to the gathering. Note, that in the example there is no common type in terms of \texttt{std::common\_type\_t} for \texttt{f1}, \texttt{f2} and \texttt{f3}:
44+
\begin{lstlisting}
45+
using T12 = std::common_type_t<decltype(f1), decltype(f2)>; // OK
46+
using T123 = std::common_type_t<T12, decltype(f3)>; // Compile-time error!
47+
\end{lstlisting}
48+
49+
If in trouble, follow the step-by-step instructions printed below!
50+
51+
\subsection{Step I}
52+
Start by finding an implementation for \texttt{Filters} that suffices the relaxed requirement
53+
\begin{lstlisting}
54+
template <typename F1, typename F2>
55+
struct Filters {
56+
Filters(F1 f1, F2 f2) {
57+
/* TODO */
58+
}
59+
60+
[[nodiscard]] auto operator()(int x) const {
61+
/* TODO */
62+
}
63+
};
64+
65+
int main() {
66+
auto f1 = [](int x) { return x % 2 == 0; };
67+
auto f2 = [](int x) { return x % 3 == 0; };
68+
Filters filters(f1, f2);
69+
return filters(5) ? 1 : 0;
70+
}
71+
\end{lstlisting}
72+
\ldots and answer the question why we need two separate template types \texttt{F1} and \texttt{F2}!
73+
74+
\subsection{Step II}
75+
Make the type of the passed argument of a filter (\texttt{int}) generic and pass it as a template parameter. You will now need to instantiate \texttt{Filters} akin to
76+
\begin{lstlisting}
77+
auto f1 = [](int x) { return x % 2 == 0; };
78+
auto f2 = [](int x) { return x % 3 == 0; };
79+
Filters<decltype(f1), decltype(f2), int> filters(f1, f2);
80+
\end{lstlisting}
81+
This is unpleasent and we will address this issue in the next step.
82+
83+
\subsection{Step III}
84+
Use a deduction guide to get rid of the explicit type naming of the filters. This is a delicate task, since we have to find the type of the argument of a passed filter. You may want to have a look at Sec.~\ref{sec:fcttraits} to find a solution for this problem.
85+
\begin{lstlisting}
86+
template <typename F1, typename F2>
87+
Filters(F1 f1, F2 f2) -> Filters<F1, F2, std::common_type_t< /* TODO */ >>
88+
\end{lstlisting}
89+
90+
\subsection{Step IV}
91+
We now generalize our solution for an arbitrary number of filters. Use variadic templates for the constructor and the deduction guide, and store the filters in a \texttt{std::vector}! Use \texttt{std::function<bool(T)>} as the value type of the vector.
92+
93+
\begin{lstlisting}
94+
template <typename T>
95+
struct Filters {
96+
std::vector<std::function<bool(T)>> filters;
97+
98+
template <typename F, typename... Fs>
99+
Filters(F f, Fs... fs): filters( /* TODO */ ) {}
100+
101+
/* TODO */
102+
};
103+
104+
template <typename... Fs>
105+
Filters(Fs... fs)
106+
-> Filters<std::common_type_t< /* TODO */ >>;
107+
\end{lstlisting}
108+
Add an sufficient implementation of
109+
\begin{lstlisting}
110+
template <typename F> void Filters::add_filter(F)
111+
\end{lstlisting}
112+
and don't forget to adopt your implementation of \texttt{Filters.operator()(T)}! (use \texttt{std::accumulate} if possible.)
113+
114+
\subsection{Step V}
115+
Can you think of an alternative to \texttt{std::function}? Why can we not use \texttt{std::common\_type} or \texttt{std::variant}?
116+
117+
\textbf{Hint:} Compare the sizes of lambdas with different captures:
118+
\begin{lstlisting}[title=\href{https://godbolt.org/z/ZBUfgY}{\texttt{godbolt.org/z/ZBUfgY}}]
119+
int capture_me = 1;
120+
std::cout << sizeof([](int x) { return x; }) << '\n';
121+
std::cout << sizeof([y=capture_me](int x) { return x + y; }) << '\n';
122+
std::cout << sizeof([y=&capture_me](int x) { return x + y; }) << '\n';
123+
\end{lstlisting}
124+
125+
\subsection{Optional}
126+
In case you are wondering what \texttt{std::common\_type} does; its rules are based on the rules for the ternary operator which can be confusing, e.g.
127+
\begin{lstlisting}[title=\href{https://godbolt.org/z/4TGmK6}{\texttt{godbolt.org/z/4TGmK6}}]
128+
struct S {};
129+
130+
template<class T, int> struct CT {
131+
operator T() const;
132+
};
133+
134+
int main() {
135+
auto a = false ? CT<int, 1>{} : CT<int, 2>{}; // OK
136+
auto b = false ? CT<int*, 1>{} : CT<int*, 2>{}; // OK
137+
auto c = false ? CT<S*, 1>{} : CT<S*, 2>{}; // OK
138+
auto d = false ? CT<S, 1>{} : CT<S, 2>{}; // Compile-time error
139+
}
140+
\end{lstlisting}
141+
Depending on what compiler you are using, the error message for \texttt{d} varies. Take a look at:
142+
\begin{itemize}
143+
\item \texttt{[over.build] \S27}
144+
\item \texttt{[expr.cond] \S6}
145+
\end{itemize}
146+
if you want to learn more.

‎exercise_wo_solutions.pdf‎

85.7 KB
Binary file not shown.

0 commit comments

Comments
 (0)