Skip to content
Snippets Groups Projects
Commit 509fd52d authored by Ansgar Burchardt's avatar Ansgar Burchardt
Browse files

presentation: class template argument deduction

parent 779a4976
Branches master
No related tags found
No related merge requests found
\documentclass{beamer}
\usepackage{listings}
\lstset{language=C++}
\title{Class Template Argument Deduction}
\author{Ansgar Burchardt}
\date{31 May 2017}
\begin{document}
\begin{frame}
\maketitle
\end{frame}
\begin{frame}[fragile]
\frametitle{Motivation}
\begin{lstlisting}
std::vector<int> xs = {1, 2, 3};
std::array<int, 3> ys = {1, 2, 3};
\end{lstlisting}
\pause
\begin{lstlisting}
std::pair<???, ???> p = {
someThing(), someThingElse()
};
\end{lstlisting}
The \lstinline|???| are unspeakable.
\pause
\begin{lstlisting}
auto p = std::make_pair(
someThing(), someThingElse()
);
\end{lstlisting}
But writing helper functions is not nice!
\end{frame}
\begin{frame}[fragile]
\frametitle{Motivation II}
C++17:
\begin{lstlisting}
std::vector xs = {1, 2, 3};
std::array ys = {1, 2, 3};
std::pair p = {someThing(), someThingElse()};
\end{lstlisting}
Yay!
\end{frame}
\begin{frame}[fragile]
\frametitle{How does it work?}
\begin{lstlisting}
template<typename T>
class C {
C(T a);
};
auto a = C(1);
\end{lstlisting}
\pause
Consider template function
\begin{lstlisting}
template<typename T>
auto C(T a) -> C<T>;
\end{lstlisting}
calling \lstinline|C(1)| returns a \lstinline|C<int>|.
\pause
Same as:
\begin{lstlisting}
template<typename T>
C<T> C(T a);
\end{lstlisting}
\pause
This is done for all constructors.
(Automatic deduction guides.)
\end{frame}
\begin{frame}[fragile]
\frametitle{The need for user-defined deduction guides}
\begin{lstlisting}
template<typename T>
class C {
C(T a);
template<typename It>
C(It begin, It end);
};
It begin, end;
auto a = C(begin, end);
\end{lstlisting}
\pause
\begin{lstlisting}
template<typename T, typename It>
auto C(It begin, It end) -> C<T>;
\end{lstlisting}
\lstinline|T| cannot be deduced from \lstinline|C(begin, end)|!
\end{frame}
\begin{frame}[fragile]
\frametitle{User-defined deduction guides}
\begin{lstlisting}
template<typename T>
class C {
template<typename It>
C(It begin, It end);
};
template<typename It>
C(It, It) -> C<typename It::value_type>;
\end{lstlisting}
\pause
With this we have two deduction guides:
\begin{lstlisting}
template<typename T, typename It>
C(It begin, It end) -> C<T>;
template<typename It>
C(It begin, It end) -> C<typename It::value_type>;
\end{lstlisting}
\begin{lstlisting}
It begin, end;
auto a = C(begin, end);
\end{lstlisting}
will use second (user-defined) one.
\end{frame}
\begin{frame}[fragile]
\frametitle{But not all is good}
\begin{lstlisting}
template<typename K, int dim>
class Vector {
Vector(std::initializer_list<K>);
};
\end{lstlisting}
Here \lstinline|dim| cannot be deduced, even with user-defined deduction guides.
(Though using \lstinline|initializer_list| already allows errors.)
\end{frame}
\begin{frame}[fragile]
\frametitle{A real example}
\begin{lstlisting}
typename<int dim, typename K>
class CNoOffset;
typename<int dim, typename K>
class COffset;
template<int dim,
typename C=CNoOffset<dim, double> >
class Grid
{
using K = typename C::...;
YaspGrid(Vec<K, dim> ur,
std::array<int, size_t{dim}> n);
YaspGrid(Vec<K, dim> ll, Vec<K, dim> ur,
std::array<int, size_t{dim}> n);
};
\end{lstlisting}
\end{frame}
\begin{frame}[fragile]
\frametitle{A real example II}
Assume there was no default for \lstinline|C| and define
\begin{lstlisting}
template<int dim, typename K>
Grid(Vec<K, dim>, std::array<int, size_t{dim}>)
-> Grid< dim, CNoOffset<dim, K> >;
template<int dim, typename K>
Grid(Vec<K, dim>, Vec<K, dim>,
std::array<int, size_t{dim}>)
-> Grid< dim, COffset<dim, K> >;
\end{lstlisting}
\pause
then
\begin{lstlisting}
Vector<float, 2> ll = {1., 1.}, ur = {2., 2.};
std::array n = {10, 10};
auto g1 = Grid(ur, n);
auto g2 = Grid(ll, ur, n);
\end{lstlisting}
work as they should.
\end{frame}
\begin{frame}[fragile]
\frametitle{A real example IV}
With default for \lstinline|C| however:
\begin{lstlisting}
auto g1 = Grid(ur, n);
\end{lstlisting}
will use \lstinline|CNoOffset<2, double>| (not \lstinline|float|).
\begin{lstlisting}
auto g2 = Grid(ll, ur, n);
\end{lstlisting}
will also use \lstinline|CNoOffset<2, double>|
instead of \lstinline|COffset<2, float>|.
\pause
Why? They use the automatic deduction guides with the default value for \lstinline|C|.
Workaround: \lstinline|enable_if| to enable constructors only for the right \lstinline|C|:
\begin{lstlisting}
template<
typename D,
typename=enable_if_t<is_same_v<D,CNoOffset<...>>>
Grid(Vec<K, dim>, std::array<int, size_t{dim}>);
\end{lstlisting}
or remove the default.
\end{frame}
\begin{frame}[fragile]
\frametitle{A real example V}
\begin{lstlisting}
FieldVector<float, 2> ll{1.f, 1.f}, ur{2.f, 2.f};
std::array n{10, 10};
YaspGrid grid{ur, n};
YaspGrid<2, EquidistantCoordinates<float, 2>>
grid{ur, n};
YaspGrid grid{ll, ur, n};
YaspGrid<2, EquidistantOffsetCoordinates<float, 2>>
grid{ll, ur, n};
\end{lstlisting}
\end{frame}
\begin{frame}
Supported in GCC-7 or later, however more complicated examples
result in internal compiler errors. GCC-8 a bit better.
\end{frame}
\end{document}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment