Commit 97e7d63c authored by Praetorius, Simon's avatar Praetorius, Simon
Browse files

Merge branch 'smallsuggestions' into 'master'

Smallsuggestions

See merge request teaching/scprog/wi2019!59
parents 88f956a6 07816f2c
......@@ -119,7 +119,7 @@ from one (high-level) language to another (low-level) language.
\begin{itemize}
\item The process of compiling is performed by a program, called the \Index{compiler}. Typical examples of compilers are \emph{g++},
\emph{clang}, \emph{Intel ICC}, \emph{MSVC}, and others.
\item The compiler gets as input a \Index{translation unit}, typically a text file containing the c++ code -- the definition of functions and classes.
\item The compiler gets as input a \Index{translation unit}, typically a text file containing the C++ code -- the definition of functions and classes.
A program typically consists of many translation units that are combined)
\item The output of the compiler is a collection of \Index{object files}, one for each translation unit.
\item To generate an executable (or a library) from these object files, the \Index{linker} combines all the objects to a single file.
......@@ -135,7 +135,7 @@ The process of compiling can be split into several stages:
symbol table with jump references.
\end{description}
On many linux distributions the c++ compiler of the GNU Compiler Collection (GCC) or the clang compiler of LLVM are preinstalled.
On many linux distributions the C++ compiler of the GNU Compiler Collection (GCC) or the clang compiler of LLVM are preinstalled.
Assume the code from the introductory example is stored in a text file \texttt{distance.cc}. This can be compiled into an executable, by
%
\begin{verbatim}
......@@ -315,7 +315,7 @@ Some remarks to the examples above:
% ==============================================================================
\section{Variable declaration and fundamental types\label{sec:data-type}}
C++ is a statically typed language (in contrast to dynamically typed languages like \eg PHP), meaning: each identifier and expression in a
C++ program has assigned a type that is already known to the compiler and this type can not be changed.
C++ program has assigned a type that is already known to the compiler and this type cannot be changed.
Examples:
\begin{minted}{c++}
......@@ -572,12 +572,12 @@ Example:
\end{minted}
(Fine if \cpp{long} is 64Bit long, wrong value if \cpp{long} is only 32Bit long)
We call an initialization of a value to a smaller type that can not represent this value a \emph{narrowing initialization} or
We call an initialization of a value to a smaller type that cannot represent this value a \emph{narrowing initialization} or
\emph{narrowing conversion}. In the example above, the compiler will not give any error and compiles fine, although the value might be wrong.
Maybe the compiler prints a warning, but not on all warning levels and this is not guaranteed.
\begin{guideline}{Principle}
Enable all warnings and stick to the c++ standard, \ie use the compiler flags \texttt{-Wall -Wextra -pedantic}, optionally you may
Enable all warnings and stick to the C++ standard, \ie use the compiler flags \texttt{-Wall -Wextra -pedantic}, optionally you may
even set the flag \texttt{-Werror} to assert an error instead of warnings.
\end{guideline}
......@@ -611,11 +611,11 @@ Some examples of narrowing conversions:
The\marginpar{[\cxx{17}]} curly braces, \ie uniform initialization, also works with the automatic type deduction \cpp{auto}. But be careful! The meaning
of the curly braces has changed in \cxx{17} and also before results sometimes in a type different from what you would expect.
\begin{minted}{c++}
auto x1 = {42}; // c++14 x1 is of type std::initializer_list<int>
auto x2 = {42}; // c++17 x2 is of type std::initializer_list<int>
auto x1 = {42}; // C++14 x1 is of type std::initializer_list<int>
auto x2 = {42}; // C++17 x2 is of type std::initializer_list<int>
auto x3{42}; // c++14: x3 is of type std::initializer_list<int>
auto x4{42}; // c++17: x4 is of type int
auto x3{42}; // C++14: x3 is of type std::initializer_list<int>
auto x4{42}; // C++17: x4 is of type int
\end{minted}
\end{rem}
......@@ -666,7 +666,7 @@ A \cpp{constexpr} variable must satisfy the following requirements:
\item the full-expression of its initialization, including all implicit conversions, constructors calls, etc, must be a constant expression
\end{itemize}
The category \emph{LiteralType} can not yet be fully explained, but especially the fundamental types discussed above are \emph{LiteralTypes}.
The category \emph{LiteralType} cannot yet be fully explained, but especially the fundamental types discussed above are \emph{LiteralTypes}.
\begin{rem}
\cpp{constexpr} variables, expressions and functions are a powerful tool within C++, available since \cxx{11} and extended in \cxx{14} and \cxx{17}.
......@@ -924,7 +924,7 @@ This structured binding does not only work for tuple-like structures, but also f
\end{minted}
\begin{rem}
Tuples (and pairs) can not be traversed like other containers. The reason is that each element in a tuple has a different type and in a loop the elements must have the same type in each iteration. Currently the standard committee discusses and extended version of a loop, like \cpp{for...(auto t : tuple)} or \cpp{for constexpr(auto t : tuple)}. But this is not yet decided. We will see later in the chaper about meta-programming how to write a loop over tuples yourself. Then you get something like
Tuples (and pairs) cannot be traversed like other containers. The reason is that each element in a tuple has a different type and in a loop the elements must have the same type in each iteration. Currently the standard committee discusses and extended version of a loop, like \cpp{for...(auto t : tuple)} or \cpp{for constexpr(auto t : tuple)}. But this is not yet decided. We will see later in the chaper about meta-programming how to write a loop over tuples yourself. Then you get something like
\begin{minted}{c++}
forEach(tuple, [](auto t) {
std::cout << t << std::endl;
......
......@@ -63,7 +63,7 @@ There are essentially two ways how to pass values/arguments to functions:
int main() {
int j = 4;
foo(j); // j can not be changed by foo
foo(j); // j cannot be changed by foo
return 0;
}
\end{minted}
......@@ -122,7 +122,7 @@ must be set to arguments starting from the last one.
\end{example}
\begin{rem}
One can not directly set a default value for the first argument and no default value for the second argument. If a default is set, for argument $n$, all
One cannot directly set a default value for the first argument and no default value for the second argument. If a default is set, for argument $n$, all
following arguments also must have a default value.
An alternative to these default values, are \emph{optional} values. This is a library extension in \cxx{17}\marginpar{[\cxx{17}]}, where the actual default
......@@ -176,7 +176,7 @@ output arguments must be passed by (non-const) reference. The intend is that you
reference to the function where it is filled with values.
\begin{rem}
There is no only-output parameter type in c++, you can always read from the output variable. This is a source of errors so that some people prefer
There is no only-output parameter type in C++, you can always read from the output variable. This is a source of errors so that some people prefer
not to use output arguments, or use pointer arguments exclusively for this purpose, so that access to the value must be done explicitly.
\end{rem}
......@@ -205,7 +205,7 @@ int& foo2() {
\end{minted}
\begin{rem}
Using \cpp{auto} return type might lead to unexpected behavior, if combined with references. The type that is returned is the raw type
Using \cpp{auto} return type might lead to unexpected behavior if combined with references. The type that is returned is the raw type
of the expression in the return statement, removing all top-level const and reference qualifiers:
\begin{minted}{c++}
auto f0(int i) { return i; } // -> int
......@@ -273,7 +273,7 @@ int main()
Some people prefer the naming \emph{deferred temporary materialization}, \ie the materialization of the value 42 happens in the \cpp{main()} when
assigned to the variable \cpp{x}.
This optimization or guarantee is especially important, if you want to return large objects created inside of the function. It is thus
This optimization or guarantee is especially important if you want to return large objects created inside of the function. It is thus
guaranteed that no expensive copy operation must be performed. (not even a move operation). The created objects simply materializes outside of
the function in the target variable.
......
......@@ -173,17 +173,17 @@ This behaviour is determined by the position of the \cpp{const} qualifier, \ie
int data = 42, data2 = 1234;
int const* i1 = &data;
*i1 = 7; // ERROR: can not modify constant data
*i1 = 7; // ERROR: cannot modify constant data
i1 = &data2; // OK: i1 now points to data2
int* const i2 = &data;
*i2 = 7; // OK: data is not const
i2 = &data2; // ERROR: can not change address of const pointer
i2 = &data2; // ERROR: cannot change address of const pointer
int const* const i3 = &data; // completely imutable
\end{minted}
Since one can not have a reference of a reference, one can also not declare a pointer to a reference (something like \cpp{int&*}), but a
Since one cannot have a reference of a reference, one can also not declare a pointer to a reference (something like \cpp{int&*}), but a
pointer is a regular type representing an address, it can be referenced, \ie
%
\begin{minted}{c++}
......
......@@ -29,8 +29,8 @@ automatically by the compiler:
Multi-dimensional arrays are written with multiple square brackets:
%
\begin{minted}{c++}
int A[2][3]; // a 2 x 3 matrix
double B[5][4][3]; // an 5 x 4 x 3 tensor
int A[2][3]; // a 2 × 3 matrix
double B[5][4][3]; // an 5 × 4 × 3 tensor
\end{minted}
%
and can be understood as arrays of arrays (a matrix is and arrays of rows).
......@@ -78,7 +78,7 @@ Example:
static_assert(SIZE(mat) == 4, "");
\end{minted}
One can not directly determine the rank of a matrix/tensor and thus number of rows and columns of a matrix without prior knowledge of the shape
One cannot directly determine the rank of a matrix/tensor and thus number of rows and columns of a matrix without prior knowledge of the shape
is not possible to detect with macros.
......@@ -142,7 +142,7 @@ library:
#include <array>
// ...
std::array<int, 3> vec1 = { 1.0, 2.0, 3.0 };
std::array vec2 = {1, 2, 3}; // with c++17
std::array vec2 = {1, 2, 3}; // with C++17
std::cout << vec1[1];
\end{minted}
......@@ -202,7 +202,7 @@ may simply overwrite the data stored at the specific memory location $\rightarro
it may lead to undefined behavior (and often produces a runtime-error of the form ``invalid pointer'').
\end{guideline}
Another problem with dynamic arrays is that you can not even see whether it is an allocated array, or just an uninitialized pointer variable. So,
Another problem with dynamic arrays is that you cannot even see whether it is an allocated array, or just an uninitialized pointer variable. So,
here again the general rule applies: initialize variables directly on declaration. If you do not yet have an address to initialize the pointer with,
set it to zero, \ie
%
......@@ -242,7 +242,7 @@ the size of the underlying data. This means that \cpp{pointer + 1} points to the
Examples:
\begin{minted}{c++}
int* vec = new int[10]; // vec points to the first element of the array
vec = vec + 1; // vec now contains the address (vec + sizeof(int)), \ie
vec = vec + 1; // vec now contains the address (vec + sizeof(int)), that is:
// vec points to the second element of the array
vec++; // vec points to the third element of the array...
delete[] vec; // ERROR: Address of vec not allocated by a direct call to new[]
......@@ -253,7 +253,7 @@ Pointers can be dereferenced, giving a reference to the data it points to. Addit
equivalent to \cpp{*(pointer + n)}.
Requirement for using pointer arithmetic is that the data has a defined size (complete types). The ``empty-set'' type \cpp{void} can be used as a pointer type,
meaning just the address without any reference to the data-type of the stored data. Since \cpp{void} does not have a size, pointers to \cpp{void} can not
meaning just the address without any reference to the data-type of the stored data. Since \cpp{void} does not have a size, pointers to \cpp{void} cannot
be used in pointer arithmetics.
......
......@@ -191,7 +191,7 @@ in that function. If you have a \cpp{const} class object or a \cpp{const&} to a
% -------------------------------------------------------------------------------------------------
\subsection{Static Members}
Static variables (class variables) or static function (class functions) are shared by all instances of that class and are introduced with the keyword \cpp{static}.
Static variables must be defined outside of the class. Since they are independent of any instance. Static members can not be initialized in a constructor.
Static variables must be defined outside of the class. Since they are independent of any instance. Static members cannot be initialized in a constructor.
%
\begin{minted}{c++}
class MyPoint
......@@ -342,7 +342,7 @@ that is also initialized by a constructor call passing two arguments.
of the constructor arguments).
\textbf{Note}: If some member variables have default initializers, like \cpp{int dim = 2;} those initializations are appended to \underline{all} constructor
initializer lists, if no other value for that variable is prescribed.
initializer lists if no other value for that variable is prescribed.
% -------------------------------------------------------------------------------------------------
......@@ -367,7 +367,7 @@ MyPoint* q2 = new MyPoint{};
\end{minted}
If there is no other constructor defined, the compiler automatically generates a default constructor with default behavior, \ie that calls the default constructor
on each member variable (and base-class). For integral can floating-point types the default initializer value is \texttt{0}, if not specified otherwise by
on each member variable (and base-class). For integral and floating-point types the default initializer value is \texttt{0} if not specified otherwise by
putting the value in the variable definition, \ie \cpp{int dim = 2;}.
If there is any other constructor defined, one can force the compiler to generate the default constructor automatically, by adding the keyword \cpp{= default} to
......@@ -385,7 +385,7 @@ public:
\subsubsection{Copy constructor}
A \emph{copy constructr} is used to create a new instance as a copy of another object. This constructors expects exactly one argument, an const lvalue-reference
A \emph{copy constructr} is used to create a new instance as a copy of another object. This constructors expects exactly one argument, a const lvalue-reference
to the class-type itself:
%
\begin{minted}{c++}
......@@ -444,7 +444,7 @@ by using the keyword \cpp{= default}, as above:
};
\end{minted}
Also, one could explicitly mark the copy constructor as \emph{deleted} to enforce that a class can not be copied. This can be accomplished by using the
Also, one could explicitly mark the copy constructor as \emph{deleted} to enforce that a class cannot be copied. This can be accomplished by using the
keyword \cpp{= delete}, similar to the default.
\begin{guideline}{Attention}
......@@ -471,8 +471,8 @@ The argument to the assignment operator thereby is the same as for the copy cons
};
\end{minted}
\textbf{Note}: You can not use the initializer-lists anywhere outside of constructors, thus especially not in assignment operators. Therefore, the copy has to
move to the function body.
\textbf{Note}: You cannot use the initializer-lists anywhere outside of constructors, thus especially not in assignment operators. Therefore, the copy has to
happen in the function body.
\begin{guideline}{Principle}
If you define a copy-constructor you should also define a copy assignment operator.
......@@ -518,7 +518,7 @@ Move constructors are used/invoked when:
\begin{itemize}
\item initialization: \cpp{T a = std::move(b);} or \cpp{T a{std::move(b)};}, where \texttt{b} is of type \texttt{T};
\item function argument passing: \cpp{f(std::move(a));}, where \texttt{a} is of type \texttt{T} and \texttt{f} is \cpp{void f(T t)};
\item function return: return \texttt{a}; inside a function such as \cpp{T f()}, where \texttt{a} is of type \texttt{T} which has a move constructor.
\item function return: \texttt{return a}; inside a function such as \cpp{T f()}, where \texttt{a} is of type \texttt{T} which has a move constructor.
\end{itemize}
The default behavior of a move-constructor is to move construct all its members from the members of the passed argument. This default move constructor
......@@ -531,12 +531,12 @@ implicitly declared only of
\item there are no user-declared destructors;
\end{itemize}
and is implicitly deleted if some data members (or base-classes) can not be moved.
and is implicitly deleted if some data members (or base-classes) cannnot be moved.
In case the default behavior would make sense but another constructor or destructor of the list above is defined, one can force the compiler to generate
the move-constructor automatically, using the keyword \cpp{= default}, as above.
Also, one could explicitly mark the move constructor as \emph{deleted} to enforce that a class can not be moved. This can be accomplished by using the
Also, one could explicitly mark the move constructor as \emph{deleted} to enforce that a class cannot be moved. This can be accomplished by using the
keyword \cpp{= delete}, similar to the default.
Similar to the copy constructor, there is a cousin of the move constructor, the move assignment operator: This should be defined whenever a move constructor
......@@ -546,7 +546,7 @@ is provided:
% -------------------------------------------------------------------------------------------------
\subsection{Destructor\label{sec:destructor}}
A destructor is kind of the opposite to a construct. It is responsible for releasing all resources allocated in any other constructor of that class, \eg
A destructor is kind of the opposite to a constructer. It is responsible for releasing all resources allocated in any other constructor of that class, \eg
to free all memory or to close opened files. A destructor is called whenever the life-time of a class end, either at the end of a scope or explicitly via
the \cpp{delete} operator.
......@@ -564,8 +564,8 @@ private:
\end{minted}
At the end of a user-defined destructor, the destructors of all member variables are called automatically.
The default behavior of a destructor is, that simply all members are destroyed using their destructors. This default behavior is automatically generated if
no user-defined destructor is provided. If any member cannot be destructed, the implicitly generate destructor is deleted.
The default destructor that simply destroys all members using their destructors. This default behavior is automatically generated if
no user-defined destructor is provided. If any member cannot be destructed, the implicitly generated destructor is deleted.
% =================================================================================================
\section{Rule of five / Rule of zero}
......@@ -621,7 +621,7 @@ Additionally, there is the access restriction \cpp{protected} that we will see l
Point p{1.0, 2.0}; // Initialization
p.x; // OK: x is a public member variable
p.a: // ERROR: a ist a private member and can not be accessed from outside the class
p.a: // ERROR: a ist a private member and cannot be accessed from outside the class
p.foo(); // OK: foo is a public member function
p.bar(); // ERROR: bar is a private member function
......@@ -638,7 +638,7 @@ have this access restriction.
\begin{rem}
Also constructors can be restricted. This allows to instantiate a class (or copy/move a class) in a specific way only. If there are no public
constructors available, the class can not be instantiated directly and one has to provide a ``factory''-function instead, \ie a static public
constructors available, the class cannot be instantiated directly and one has to provide a ``factory''-function instead, \ie a static public
member function that constructs and returns the instantiated class.
\end{rem}
......
......@@ -90,7 +90,7 @@ The syntax to declare a function template:
\end{minted}
It simply starts with the keyword \texttt{template} and in angular brackets \texttt{<...>} a comma separated list of template parameters.
The argument \texttt{NAMEx} is called \emph{template parameter} and must be a valid name in c++. The argument is introduced with either the
The argument \texttt{NAMEx} is called \emph{template parameter} and must be a valid name in C++. The argument is introduced with either the
additional keyword \texttt{typename} or \texttt{class} for type-parameters (there is no difference of these two keywords).
\begin{rem}
......@@ -147,7 +147,7 @@ The type deduction thereby is very similar to the \cpp{auto} type deduction from
Actually, in C++ first the template parameter deduction was invented and later the auto-type deduction was added with \cxx{11}.
\begin{rem}
Argument type deduction only works, if all the types can be deduced uniquely from the function parameters. In the example above, we have
Argument type deduction only works if all the types can be deduced uniquely from the function parameters. In the example above, we have
declared a function template with two parameters and have specified both with the same template parameter \texttt{T}. Thus, we have to
pass two arguments of the same type to the function template in order to allow the template parameters to be deduced from the
function parameters:
......@@ -155,7 +155,7 @@ Actually, in C++ first the template parameter deduction was invented and later t
\begin{minted}{c++}
double a = 1.0;
float b = 2.0f;
abs_difference(a,b); // ERROR: can not deduce template parameters
abs_difference(a,b); // ERROR: cannot deduce template parameters
\end{minted}
%
The parameter \texttt{T} could be either deduced to \cpp{double} or to \cpp{float}.
......@@ -253,7 +253,7 @@ where \texttt{TYPES...} is a list of concrete types (without the keyword \texttt
\begin{rem}
With \marginpar{[\cxx{17}]}\cxx{17} the class template parameters can be automatically deduced from the class constructor arguments. This
is called \emph{class template argument deduction}. Similar to argument type deduction for function templates the template parameters
are deduced from the arguments passed to a constructor of the class template. This works, if all class template parameters are related to
are deduced from the arguments passed to a constructor of the class template. This works if all class template parameters are related to
a constructor parameter:
%
\begin{minted}{c++}
......@@ -265,7 +265,7 @@ where \texttt{TYPES...} is a list of concrete types (without the keyword \texttt
but
%
\begin{minted}{c++}
std::vector v2(7); // ERROR: type can not be deduced. The constructor argument is
std::vector v2(7); // ERROR: type cannot be deduced. The constructor argument is
// just the size of the vector, no value.
\end{minted}
......@@ -299,7 +299,7 @@ The following example defines a class template of a container with fixed number
\end{minted}
\begin{rem}
Not all types are allowed as non-type template parameters. It must be possible to uniquely evaluate those types at compile-type. Therefore the c++
Not all types are allowed as non-type template parameters. It must be possible to uniquely evaluate those types at compile-type. Therefore the C++
standard has restricted non-type template parameters to integral types, enums, characters, and pointer types.
\end{rem}
......
......@@ -152,7 +152,7 @@ Without the \emph{capture} clause, it looks like a regular function definition.
\item \emph{parameters} is a list of function parameters including its types and qualifiers (like in regular function declarations)
\item \emph{ReturnType} is the (optional) (trailing) return type of the function, that can depend on the types of the function parameters
It can be omitted, resulting in the automatic return type deduction, like in functions returning \cpp{auto}.
\item The function body may contain any sequence of c++ statements and (optionally) a return statement.
\item The function body may contain any sequence of C++ statements and (optionally) a return statement.
\end{itemize}
\begin{example}
......@@ -189,7 +189,7 @@ Without the \emph{capture} clause, it looks like a regular function definition.
\end{example}
The capture list is very similar to a list of constructor argument of the functor. All variables in that list introduce a local
member variable, that can be used inside the lambda expressions function body. Any other variable can not be used there, since it
member variable, that can be used inside the lambda expressions function body. Any other variable cannot be used there, since it
generates an unnamed functor class with an \cpp{operator()} member function that is called on evaluation.
Using the capture list, a connection to the surrounding scope can be established. The following values are possible in the capture list:
......@@ -237,7 +237,7 @@ but, we do not have a name for the type of the parameter like \texttt{S} in the
\end{rem}
Similar to classical templates and the \cpp{auto} placeholder in variable declarations, the function parameters in generic lambdas
can be qualified with \cpp{const}, reference and pointer. But they can not be used as placeholders in other templated types, \eg
can be qualified with \cpp{const}, reference and pointer. But they cannot be used as placeholders in other templated types, \eg
\cpp{std::vector<auto>} is not allowed as function parameter in generic lambdas.
\begin{rem}
......@@ -261,5 +261,5 @@ invented template parameter for each placeholder is appended to the template par
void f2(auto const& arg); // same as template<class T> void f2(T const& arg)
\end{minted}
%
This is especially useful, if the actual type of the argument is irrelevant, but the algorithm allows to generically pass arguments of different
This is especially useful if the actual type of the argument is irrelevant but the algorithm allows to generically pass arguments of different
type.
......@@ -297,7 +297,7 @@ The category is represented by empty classes, forming a hierarchy that represent
\item Directly take the difference between \texttt{first} and \texttt{last} it the iterator is a \emph{Random Access Iterator}
\end{enumerate}
Since the difference is only possible if the type supports this operation, we can not simply use an \cpp{if - else} branching. we have
Since the difference is only possible if the type supports this operation, we cannot simply use an \cpp{if - else} branching. we have
to implement two function, differing only in the iterator category:
%
\newpage
......@@ -444,13 +444,13 @@ The output-iterator is incremented only if the predicate returns \cpp{true}.
\subsubsection{Back-inserter}
The problem with the copy algorithm is that we need to resize the output container before we can copy into it. In case of \cpp{copy_if} we even do
not know how many elements are copied. It would be better, if the algorithm itself could ``resize'' the container to the required size. But we
not know how many elements are copied. It would be better if the algorithm itself could ``resize'' the container to the required size. But we
do not get a container as input, but an iterator. This iterator has no functionality to resize the underlying container. It often does not even has
a reference to the container it points into.
A workaround for this problem is to use a different output-iterator. Not an iterator directly pointing to elements of the output-range, but a special
iterator wrapper that performs on assignment to the dereferenced iterator an \cpp{insert()} or \cpp{push_back()} operation. The corresponding
wrapper type is called \cpp{std::back_insert_iterator} ans is created using the function \cpp{std::back_inserter}.
wrapper type is called \cpp{std::back_insert_iterator} and is created using the function \cpp{std::back_inserter}.
%
\begin{minted}{c++}
#include <algorithm>
......@@ -504,7 +504,7 @@ constructed from an output-stream object, like \cpp{std::cout}, \cpp{std::cerr}
a delimiter separating the printed elements.
The \cpp{std::ostream_iterator} is a model of a \emph{single-pass} \cpp{OutputIterator}, thus can be ``traversed'' only once. In a second traversal
the state of the output-range is already changed and we can not go back.
the state of the output-range is already changed and we cannot go back.
% -------------------------------------------------------------------------------------------------
......
......@@ -116,8 +116,8 @@ Or you pass the values as integral constants:
\end{minted}
\subsubsection{Recursive programming}
C++ is a statically typed language, meaning: the type of a variable or an alias can not be changed once it is set. And everything must
have a type. This prevents from implementing something like loops where you update a counter during iteration. This makes it more
C++ is a statically typed language, meaning: the type of a variable or an alias cannot be changed once it is set. And everything must
have a type. The prevents from implementing something like loops where you update a counter during iteration. This makes it more
difficult to do programming with templates. Everything has to be implemented using recursion instead of iteration.
In order to illustrate a recursive algorithm implemented using templates, we consider the factorial computation.
......@@ -281,7 +281,7 @@ with assembler output
movl $5, -4(%rbp)
\end{verbatim}
This restriction is removed in \cxx{14} and you can write loops, use if-then-else, introduce local variables and much more. But, you can not do
This restriction is removed in \cxx{14} and you can write loops, use if-then-else, introduce local variables and much more. But, you cannot do
all that is possible with classical functions. Especially, your arguments and return types must be \emph{LiteralType}s like scalar types or
trivial classes.
......
......@@ -16,7 +16,7 @@
\usepackage{todo}
%\usepackage{dingbat}
\usepackage{mdframed}
\usepackage{makeidx}
\usepackage{imakeidx}
\usepackage{algorithm}
\usepackage[noend]{algpseudocode}
\usepackage{tcolorbox}
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment