Programming Language Concepts Using C and C++/Parameterized Types

Achieving reuse through inheritance may at times lead to an explosion in the number of classes. Consider defining stacks of different types. Using the inheritance approach, we would start out with defining an abstract class containing the attributes common to all stacks and get people to derive their specialized stack classes from this class. Problem with this approach is&mdash;since operation signatures are type dependent&mdash;not much can be reused.




 * }

A stack of  objects using a similar implementation technique would mean all occurrences of   must be replaced with , which leaves very little room for reuse. Way out of this is defining a stack of something that can be interpreted as a stack of anything. In C/C++, that something is ; in Java and C#, it is the root class.



! style="text-align:left;" | Example: Genericness in pre-1.5 Java.
 * }

In this pre-1.5 Java implementation we can create and use stacks of various types without having to rewrite the functionality in different classes. This solution has a serious flaw, though. Users of  are responsible for correct use of the class. Errors such as pushing a  onto a stack of  s are tolerated by the compiler and cannot be caught before run-time. After all, both classes are derived from  and their objects are in that aspect alike.

So we need to take another step for achieving reuse without sacrificing type safety. The answer is provided by introducing a new feature into the language: parameterized types. Using parameterized types we can get higher levels of reuse by collapsing a base class and a number of derived classes into a single class without compromising type safety. Instead of having an abstract class and various specialized classes deriving from this abstract class, we now have a single parameterized class.



! style="text-align:left;" | Example: Generic classes in Java.
 * }

Replacing inheritance in the first scenario with parameterized types in the final scenario might make you think parameterized types and inheritance are alternatives to each other. That would be wrong, though. These two features are actually complementary reuse tools: while inheritance is used to express the is-a relation between classes found at different levels of the class hierarchy, parameterized types are used to group classes found at the same level. In other words, inheritance&mdash;since it adds a new level&mdash;is "vertical", whereas parameterized types&mdash;since they work by collapsing classes at the same level&mdash;are "horizontal".

Thanks to inheritance [and polymorphism] we organize these types into a hierarchy that better reflects our perception of them. After all, aren't real numbers actually complex numbers with no imaginary part? Aren't rational numbers real numbers that can be expressed as the ratio of two integers? ... This is further strengthened by the use of parameterized types. In math, we never speak of vectors with different content type as different concepts; there is only one definition for vector.

Note that the use of a collection type in the previous presentation is not by chance. Genericness is generally regarded as parameterization of collection types. But many times we need to reuse the functionality of a single function working on a parameterized type. Generic algorithms&mdash;such as,  ,  ,  ,  ,  , and so on&mdash;implemented as part of the standard library are examples to this.

Template Compilation Models
Once a parametric type is implemented it is typically used by indefinitely many clients. This means the same module will have to be re-used to create objects of indefinitely many types. Well, not really! At least not so in the C++ world.

Separation Compilation Model
In the separation compilation model, template file is compiled and this compiled file is supplied to the clients. Given the diversity of object file formats and instruction sets, for a language like C++ this seems to be a rather elusive option.

A first attempt at solving this problem dictates the implementer to maintain a separate object module for each platform. Given the possibility of multiple platforms coexisting in the same company or clients willing to switch to/add a new platform, this option turns out to be a maintenance nightmare.

Interoperability between various platforms is made possible by adapting a common file format and compiling the source module into intermediate code. This scheme is used by languages like Java and C#, where the clients, regardless of the platform, use intermediate code equivalent of the source module. Needless to say this technique is not well-suited to C++. Therefore the separation compilation model is not widely implemented by C++ compilers.

With the separation compilation model, the class template definition and the definitions of its inline member functions are placed in a header file, whereas the definitions of the member functions that are not inline and static data members are placed in a program text file. With this model, the definitions for a class template and its members are organized in the same way we organize the definitions of non-template classes and their members.



In an environment where the separation compilation model is supported, we need to make some changes in our code.

Implementation of member function definitions that are not inline are moved into a file named, say StackTemplate.cxx.

You may choose to use a more selective version of the  keyword.

StackTemplate StackTemplate.cxx

Inclusion Compilation Model
In the inclusion compilation model, the definition of the member functions and static members of class templates must be included in every file in which they are instantiated.

Definition: The act of using a parameterized type is called instantiation.

There are some drawbacks in providing the definitions for the members of a class template in a header file. The member function definitions may be quite large and may describe implementation details that the user may want to ignore or that we, as implementers, may want to hide from our users. Moreover, compiling the same template definitions across multiple files can add to the compile-time of our programs unnecessarily. The separation compilation model, if available, allows us to separate the class template interface (that is, the class template definition) from its implementation (that is, the definitions of its member functions and static data members).

Interface / Implementation
StackTemplate

Here is where we begin the definition of our class template. The list surrounded by ‘<’ and ‘>’ includes the template parameter list, which can have a combination of type parameters and non-type parameters.

A template type parameter consists of the keyword  or the keyword   followed by an identifier. In a template parameter list, both keywords have the same meaning. They indicate that the parameter name that follows represents a built-in or user-defined type. In this case, our single parameter represents the type of information held in the stack.

A template non-type parameter consists of an ordinary parameter declaration. A non-type parameter indicates that the parameter name represents a potential value. This value represents a constant in the class template definition.

Notice the explicit template argument following the function name. This syntax is used to specify that the  declaration refers to an instantiation of the function template. That is, there is a one-to-one mapping between the instantiations of the class template and its friend. In our case, the only friend of  is   no other overloaded definitions for the shift operator has any special access rights. There are two other types of friend declarations that may appear within a class.


 * Many-to-one: Friend class/function is declared to be friend to all instantiations of the class template. For example,




 * }


 * declares functionName to be friend to all  instantiations.


 * One-to-many: For each instantiation of the class template, all instantiations of friend class/functions are friends. For example,




 * }

declares all instantiations of functionName to be friends to each instantiation of.

The following constructor definition is equivalent to. In both cases, a  object is constructed with a capacity of. But, there is a subtle difference. This is due to the execution order of constructors. Before the execution of an object’s constructor, all of its base class default constructors and member object default constructors are invoked. So, any updates you make to a member object in the constructor body will probably override the value provided in the relevant constructor. That may sometimes turn out to be a little costly. We may end up initializing the same object twice for different initial values. (Technically, it is not initialization that we do inside the constructor body but assignment.) For instance, the above code will work as follows:

In this scenario, we end up creating a  object and having to resize it. Member initialization list provides us with a way to remove this source of inefficiency. Instead of calling the default constructors, we may pass arguments to the constructors and create the object with the required properties. The compiler in such a case will call the relevant constructor.
 * 1)   constructor is called.
 * 2) Before entering the constructor body, the default   constructor for   is called. This will create a   of size and capacity both equal to 0.
 * 3) The body of the   constructor is executed. This will, depending on the value of the parameter, adjust the initial capacity of the   object with the parameter and probably resize it.

The below constructor definition will work as follows:


 * 1) Constructor of   is called.
 * 2) Before entering the constructor body,   object is created by calling the relevant   constructor. The   parameter passed to the   constructor is further passed as an argument to the   constructor. This will basically create a   with an initial capacity equal to , which is what we did inside the constructor body in the first version.

Note the difference between the signature of the first two functions and the last one. Since the result is returned in their sole parameter the first two declare call-by-reference parameters. Because we do not have such a requirement the last function, on the other hand, declares a call-by-value parameter. As is explained in the Object-Based Programming chapter, this could also be accomplished by the following declaration.

is one of the abstract container types provided by the C++ standard library. Like an array, it holds an ordered collection of elements of a single type. It is represented in a contiguous area of memory, which makes random access possible. Unlike an array, however, size of a  can grow dynamically. When the  needs to grow itself, it allocates additional storage capacity beyond its immediate need&mdash;it holds this storage in reserve. You can try the following to see how a vector grows in your system.

Vector_Growth.cxx

Note the difference between  and. returns the maximum number of elements that a  object can hold before it needs to regrow itself. On the other hand,  returns the number of elements currently held in the vector. ( inserts an element to the back of the container.) Other major container types provided by the C++ standard library are,  ,  , and. For more check the Container Types section.

Whoops! What have we got here? Definition of a class member function inside a header file?!. It certainly goes against the information hiding principle! Unfortunately, we cannot avoid it in this case. This is a consequence of the way templates are supported by C++ compilers. For more on this, check the Template Compilation Models section.

Sometimes we want the user of a container data type to be able to access, one at a time, each and every component in the container. For an array, it would be very simple: start from the first component and each time you want to move on to the next component proceed by increasing the index value by one; for a linked list all you have to do is to follow the link to the next component; for a sequential file issuing a read operation will do the job. Although the way you achieve is different the idea of traversing an ADT is an abstract operation common to many of them. In object-oriented programming languages such an operation is provided by means of iterators.

Definition: An iterator is an auxiliary data structure created with the sole purpose of permitting access to the values in a container through a sequence of simple operations, while hiding from the user of the iterator the actual implementation of these operators.

In C++, an iterator is defined to be a "pointer" to the component’s data type. and  are used to locate the beginning and end of the container, respectively. Along with an iterator used to traverse the container in the forward direction, one can also have a reverse iterator, an iterator that starts traversal from the last component and moves toward the beginning. For such an iterator,  and   methods are used to locate the two ends of the container.

Insert iterator figure here

For a forward iterator,  accesses the next element in the container, while it accesses the previous component in the case of a reverse iterator. Using  to dereference the iterator yields the contents of component currently being visited. (Do not forget that the iterator is in fact a pointer!)

Next line defines a reverse iterator on the  and sets it to point to the last component.

Each and every class template member function definition must be preceded by the  keyword and the template parameter list.

Parameter names stay in scope throughout the definition of the following class or the member function. That’s why we can use different names for the same parameter.

In order to avoid modifications being made through an iterator we can define constant iterators. Any attempt to modify components of the underlying vector through these iterators will be caught by the compiler.

Note this applies only to attempts made using these iterators. Making modifications using other means or even other non-constant iterators is still a possibility.

Test Program
StackTemplateTest.cxx

Next two lines are examples to instantiation of our class template. As a result of elaborating these statements compiler, or the compiler-linker pair, will synthesize code required for two classes. In order to convince yourself about this add lines that defines and uses a stack of a different type and observe the increase in size of the resulting executable.

Container Types
Container types supported by the Standard Template Library (STL) can be divided into two: linear containers (sequences), which hold an ordered collection of elements, and non-linear containers, which support efficient query and retrieval of an element. The former includes the,  , and   classes while the latter group   and. One can also add the restricted list classes,   and   to the former group.

In addition to the basic relational operators, functions creating iterators, and container-specific operations, all container types conform to the Orthodoz Canonical Form and support,  ,  ,  ,. Functionality offered by a particular class is brought in by an  directive that takes the container type as the file name.

Sequences (Linear Containers)
STL supports three types of sequences:,  , and. All capable of dynamically adjusting their sizes,  is designed to be a random-access container,   is the typical linked structure, and   provides a cross between the two.

Two important operations supported by the linear containers are insertion and deletion of items. Named  and , these operations make use of iterators. can be used in three ways. The first version returns an iterator to the element that has just been added while the others return.


 * : Inserts  before the position indicated by the iterator passed in the first argument. Note, since   locates the iterator beyond the container,   inserts   to the end of.
 * : Inserts  as many as   times before the position indicated by the iterator passed in the first argument.
 * : Inserts a closed-open range of values delimited by the second and third arguments before the position indicated by the iterator passed in the first argument. For instance,  inserts the first four elements of   to the end of.

Similarly,  can be used in two ways. Both versions return an iterator that shows the element after the last erased element.


 * : Removes the item indicated by the iterator passed in the argument.
 * : Removes all items of  delimited by the range specified in the arguments. The special case where all items of the container is removed can also be accomplished by the   function.

Two functions, both special to list, remove elements that have a certain property.


 * : Removes all elements of the list that are equal to.
 * : Removes all elements of  that satisfy the unary predicate&mdash;actually, a function object impersonating as a  -returning function&mdash;provided as its sole argument.

Shorthands are provided for some of the more commonly used invocations of  and. These are given below.

Given the cost of item insertion/removal due to shifting, it is no surprise that  does not support   and.

The two ends of the sequence are accessed by means of the  and   functions.

Observe that the container-specific functions reflect the nature of the underlying sequence. Thanks to their random-access support both  and   have functions,   and , for accessing elements using index values. Since  and   increase their size by one as new items are inserted, neither supports capacity and reserve.

Signatures of the -specific functions along with what they do are given below. Wherever required, a binary predicate, is used in determining the ordering criterion utilized in the algorithm.


 * & : Merges   into the list, both of which are sorted. If not given ordering is done by.
 * & : Sorts the list. If not given ordering is done by <.
 * : Inserts  into   at the location given by the iterator in the first argument.
 * : In addition to inserting  this version removes all elements at locations between   and.
 * & : Removes all consecutive duplicates in the list. If not given equality of consecutive elements are tested using.

Container Adapters
In addition to the sequence types mentioned in the previous section, STL provides support for three restricted lists by means of adapter classes. These classes and their operations are given in the table below. Note that iterator creating functions, which would enable us to access and modify each and every element in the relevant data structure, are not in the table.

Associative (Non-linear) Containers
STL supports two types of associative containers:  and. The former is used as a fast lookup structure relating a key with a value, whereas the latter is used to implement the mathematical notion of sorted sets.

Neither container type allows duplicates: it is not possible to relate a particular key with more than one value; a set cannot contain more than one copy of an object. In case duplicates are required one should use multimap and multiset, which are map and set with the no-duplicates criterion removed.

Fundamental operations supported are,  , and.


 * & : Inserts key-value  /  only if it does not exist in the  / . This function returns an iterator-success pair, where the iterator part indicates the location of insertion and the success part describes whether the operation has successfully been inserted or not.
 * : Inserts all items found in [, ).
 * & : Inserts  /  after the location indicated by   and returns an iterator to the item just inserted. Note the location of insertion passed is just a suggestion.


 * : Erases the element indicated by.
 * : Erases all elements in the range between  and.
 * & : Erases all elements that have the value  / . This function returns the number of entries deleted, which can be zero or one in a   or   whereas in a   or   it can be more than one.


 * & : Returns an iterator to the related entry in the  /  if it exists. Otherwise, it returns an iterator to the end of the container.

As in the  and   classes one can also use the subscript operator  for finding and inserting an entry in a. One should however be aware of the differences. First of all, both insert and find provide means for flagging unsuccessful operations. As a result of looking up a non-existing key in the,   returns an iterator to the end of the   without making any modification in the  , whereas   makes an entry relating the key with a default value. Also, thanks to the second version,  enables multiple entries to be inserted in a single application of the function while this is limited to one in the case of.



! style="text-align:left;" | Example: Fundamental operations on maps.
 * Next line creates a  and initializes it with the contents of the array named.
 * Next line creates a  and initializes it with the contents of the array named.
 * Next -loop populates the   with five more entries.
 * Next -loop populates the   with five more entries.
 * Next line attempts to insert an already existing key, which causes the value in the second part of the pair returned from insert to set to.
 * Next line attempts to insert an already existing key, which causes the value in the second part of the pair returned from insert to set to.
 * Next application of  inserts three key-value pairs found in   into.
 * Next application of  inserts three key-value pairs found in   into.
 * If you enter a word that happens to be missing in our, next line will return an iterator to the end of the  , meaning the lookup did not return a value. Otherwise, it returns an iterator to the relevant entry, which is a key-value pair.
 * If you enter a word that happens to be missing in our, next line will return an iterator to the end of the  , meaning the lookup did not return a value. Otherwise, it returns an iterator to the relevant entry, which is a key-value pair.
 * In case a non-existing key is looked up in the map, using the  operator instead of find will cause an entry to be made for the key in question. The corresponding value inserted assumes the default of the second part's type.
 * In case a non-existing key is looked up in the map, using the  operator instead of find will cause an entry to be made for the key in question. The corresponding value inserted assumes the default of the second part's type.
 * }

Other operations applicable on an associative container include the following.


 * : Returns the number of occurrences of /  as the key part of the entries in the   or in the.
 * : Returns a pair of iterators that has  as its part of the key-value pair or   as the element value.
 * & : Returns an iterator to the smallest value that is greater-or-equal to (greater than)  /.

Generic Functions in STL
Strength of the seemingly thin interface offered by different container types is augmented by the use of generic functions of STL. These functions make heavy use of iterators for expressing the boundaries of the container. Instead of, which would sum up the elements of  , we have  , which sums up the elements in [ ,  ). The second version is more flexible in that it enables us to apply the generic function not only on the whole container but also on a part of it. In some functions, further specialization can be provided by passing a function object to be applied on the elements of the container.



! style="text-align:left" | Example: Applying a generic function on a part of a container.
 * Inclusion of  and   are required for  .   is required for multiplies.
 * Inclusion of  and   are required for  .   is required for multiplies.
 * Next line sums up all elements, except for the first and the last, of  and stores the result in.
 * Next line sums up all elements, except for the first and the last, of  and stores the result in.
 * Next application of  finds the product of all elements in.
 * Next application of  finds the product of all elements in.
 * }

A helpful hint in dealing with the complexity of the generic functions in STL is the naming of functions that take predicates. For instance,  returns the number of elements in [,  ) equal to  . Conditional form of this function,  , basically does the same thing: it returns the number of elements in [ ,  ) that satisfy. Other functions that come with a conditional form are given below.


 * : Returns an iterator for the first occurrence of  in the range delimited by   and  . If   is not found   is returned.
 * : Removes all elements in [, ) that are equal to  . Note neither versions&mdash;that is,   and  &mdash;do any actual deletion from the underlying container. As elements that do not satisfy the (explicitly or implicitly stated) criterion are seen, they are moved to the front of the current container. Any actual deletion is meant to take place upon application of an   following either one of   or  . Both functions return an iterator to a position that comes as many as the number of removed elements before the end.



! style="text-align:left" | Example: Peculiarity of  and.
 * Next line "removes" all elements in  that are equal to  . Upon execution of ,   will have   as its content. The returned iterator will be pointing at the second  . In order to actually complete the deletion, we must execute an.
 * Next line "removes" all elements in  that are equal to  . Upon execution of ,   will have   as its content. The returned iterator will be pointing at the second  . In order to actually complete the deletion, we must execute an.
 * }

Another useful way to figure out more about generic functions in STL is to spot those functions that work their magic on a copy of the original container. Such functions have  somewhere in their names. For instance,  moves those values in the original container that do not satisfy the stated criterion to another container and returns an iterator to the end of the resulting container. Other functions working in a similar fashion include,  ,  ,   &  ,   &  , and   &.



! style="text-align:left;" | Example: Copying functions.
 * }

One other group of functions involve generalizations of certain container-specific functions. For instance, while  &   merges two sorted lists, generic function   merges any two sorted containers. Other functions in this group include,  ,  ,  ,   ,  ,  ,  ,  ,  , and.



! style="text-align:left;" | Example: Using the generalized versions of container-specific functions.
 * If  occurs in , next two lines insert   right before the first occurrence of -1. Otherwise,   is inserted at the end of.
 * If  occurs in , next two lines insert   right before the first occurrence of -1. Otherwise,   is inserted at the end of.
 * The following definition create a list using the contents of the  in reverse order.
 * The following definition create a list using the contents of the  in reverse order.
 * Next three lines delete all items in between the first and second occurrences of, including the  's. Notice&mdash;since there is no random access support&mdash;unlike in  s and  s, we cannot use iterator arithmetic [that is, we cannot use + and -] while using list iterators. Hence is the use of   following a.
 * Next three lines delete all items in between the first and second occurrences of, including the  's. Notice&mdash;since there is no random access support&mdash;unlike in  s and  s, we cannot use iterator arithmetic [that is, we cannot use + and -] while using list iterators. Hence is the use of   following a.
 * Next three lines find the third smallest item in a deque created from a previously created list. Note we can now use iterator arithmetic.
 * Next three lines find the third smallest item in a deque created from a previously created list. Note we can now use iterator arithmetic.
 * Next four lines merge two sorted sequences into a single one. Observe that the resulting sorted sequence is populated starting from its end. Note also the list, initially created empty, is later resized to take as many as one more than the total number of elements. In the process, each slot is initialized to.
 * Next four lines merge two sorted sequences into a single one. Observe that the resulting sorted sequence is populated starting from its end. Note also the list, initially created empty, is later resized to take as many as one more than the total number of elements. In the process, each slot is initialized to.
 * }

Yet another group comprises the classical higher-order functions:,  ,  , and. These functions do the equivalent of,  ,  , and   functions provided in functional programming languages.



! style="text-align:left;" | Example:
 * Next line processes all elements in the range by applying the  function to each element. Passing another function in the third argument will change the side effect created by.
 * Next line processes all elements in the range by applying the  function to each element. Passing another function in the third argument will change the side effect created by.
 * maps a given sequence to another. Nature of the mapping is determined by the last argument, which can be a unary or a binary function. The result is stored into the sequence whose starting point is given in the third argument.
 * maps a given sequence to another. Nature of the mapping is determined by the last argument, which can be a unary or a binary function. The result is stored into the sequence whose starting point is given in the third argument.
 * }

Finally, one can also utilize generic functions that treat a container as a set or a heap, respectively. In the former group, we have,  ,  , and. The latter group includes,  ,  , and   functions. Set functions take two pairs of iterators to delimit the containers to work on and an iterator pointing at the starting location of the resulting set. On the other hand, heap functions take a single pair of iterators to determine the container. All functions&mdash; or  &mdash;come in two flavors: one that assumes   is used as the ordering criterion in forming the container and one that takes an extra function that may serve the same purpose.

Function Objects
An intuitive notion lacking in C++, like almost any other imperative language, is the treatment of functions as first-class values. It's not possible to pass around and return functions; one must resort to using pointer-to-functions, instead. This section offers an alternative solution to this by introducing function objects, objects that look like functions. Instead of using functions we use instances of a class that overloads the function call operator.

Definition: A function object is an instance of a class that overloads the function call operator. Function call operator encapsulates what normally would be encapsulated as a function.

Following a selection of standard function objects supported by C++, we provide an application of the concept in simulating local functions.

Interface
Polynomial

Thanks to the simple structure of  objects&mdash;only primitive type fields&mdash;we do not have to write a copy constructor or an assignment operator. Behavior of the compiler-provided default will suffice. Add to this the fact that we don't acquire any outside resources, it becomes clear we don't need to provide a destructor function, either.

But the assignment operator is still there and will serve to assign both s and  s to a   object. What makes this magic work is the implicit conversion of a  to a   object. If you take a closer look at the previous constructor, you’ll see that we can create a  object by simply passing a single   value. Compiler will take this as a conversion tool and use for -to-  conversions. So, anywhere a  is required but a   is used compiler will silently convert the   value to a   object. In doing so it will use the constructor listed above.

This [implicit conversion] takes away our freedom of ordering the arguments sent to the constructor. Say, we change its semantics so that the first parameter stands for the coefficient of the second-degree component, the second the coefficient of the first-degree component and the last the constant. This arrangement has a rather unexpected consequence. Take a look at the following C++ fragment:

The  value   is converted to a   using the relevant constructor and   will be assigned to. Very unlikely what we really wanted!

// Polynomial(const Polynomial& existing_pol); // ~Polynomial(void); // Polynomial& operator=(const Polynomial&);

Given the above explanations, one may think that the following  declaration is superfluous. Well, not really! Because the object the message is sent to is not implicitly converted.

Next line is a declaration that will make  objects look like functions, which will give an illusion of functions being treated as first-class citizens. This is achieved through overloading the function call operator.

Thanks to the implicit conversion mentioned above, we no longer have to have three functions to overload the  operator; two will be enough.

Implementation
Polynomial.cxx

This is what makes instances of  function objects:   is overloaded to return the value of the polynomial at a given point.

Test Program
Polynomial_Test.cxx

Now that a  value is implicitly converted to a  &mdash;remember the first constructor&mdash;following assignment can be seen as addition of four  s. Assuming left-to-right, sequential evaluation; 2.0&mdash;a polynomial that has 0.0 as the coefficient of first and second order terms&mdash;is added to , to the result of which is added the. Finally,  is added to the temporary value obtained from the summation of the first three terms.

Note the following&mdash;although it looks more like calling functions&mdash;is an application of the function call operator defined in.

Running the Test Program
Filter.cxx

Predefined Function Objects
Predefined function objects are generally used in coordination with generic functions in STL, which are a bunch of function templates whose implementations require assistance from their users. To give an example,  requires a function object that is used for comparison purposes; if not passed such an object, it uses the less-than operator of the underlying type, which means you should implement the less-than operator. Passing different function objects for the same underlying type can be used to modify the ordering criterion used.

Arithmetic Function Objects
The predefined arithmetic function objects support addition, subtraction , multiplication , division , modulus , and negation.

Relational Function Objects
The predefined relational function objects are equality, inequality , greater than , greater than or equal , less than , less than or equal.

Logical Function Objects
The logical function objects supported are and, or , and the negation functions.

Simulating Local Functions
Local classes together with function objects can be used to simulate local functions. Using local classes provides protection from outside the current function whereas overriding the function call operator complements this by giving a sense of using functions.

Local_Function.cxx

is a function template that we can use to instantiate functions that sort specific type of data, which is determined at the point of calling the function. On line 56 of the current program, for instance, a call using an array of  s is being made, which means the compiler or the compiler-linker pair will synthesize a version of the following function that takes an array of  s.

Note comparison of the current array element with the first element of the array slice means we must make sure the less-than operator of the component type is implemented.

randomly reorders the elements of an iterable container marked off by its first and second arguments. In other words, this function comes up with a permutation of the range marked with its arguments. It should be noted the range is closed-open. That is, the first argument is included in the range while the second argument is excluded.

Note there is a second version of this function that takes a random number generator as its third argument, which is used in the process of shuffling the elements.