10. Subroutines

Introduction

// NOTE: Whilst it is perfectly valid to use Standard C Library, or GNU C Library, routines in
// C++ programs, the code examples here will, as far as possible, avoid doing so, instead using
// C++-specific functionality and idioms. In general:
// * I/O will be iostream-based [i.e. no 'scanf', 'printf', 'fgets' etc]
// * Container / iterator idioms based on the Standard Template Library [STL]
//   will replace the built-in array / raw pointer idioms typically used in C
// * Boost Library functionality utilised wherever possible [the reason for
//   this is that much of this functionality is likely to appear in the next
//   C++ standard]
// * Error detection/handling will generally be exception-based [this is done
//   to keep examples simple. Exception use is optional in C++, and is not as
//   pervasive as it is in other languages like Java or C#]
// C-based solution(s) to problem(s) will be found in the corresponding section of PLEAC-C/Posix/GNU.

#include <iostream>

// 'greeted' defined outside of any namespace, class or function, so is part of the
// global namespace, and will be visible throughout the entire executable. Should it
// be necessary to restrict the visibility of this global identifier to the current
// 'compilation unit' [i.e. current source file] then the following may be used:
//
//     namespace { int greeted = 0; }
//
// The effect is similar to using the 'static' keyword, in this same context, in the C
// language.

int greeted = 0;

int howManyGreetings();
void hello();

// ----

int main()
{
  hello();

  int greetings = howManyGreetings();

  std::cout << "bye there!, there have been "
            << greetings
            << " greetings so far"
            << std::endl;
}

// ----

int howManyGreetings()
{
  // Access 'greeted' identifier in the global namespace using the scope resolution
  // operator. Use of this operator is only necessary if a similarly-named identifier
  // exists in a 
  return ::greeted;
}

void hello()
{
  // Here 'greeted' is accessed without additional qualification. Since a 'greeted' identifier
  // exists only in the global namespace, it is that identifier that is used
  std::cout << "high there!, this function has been called "
            << ++greeted
            << " times"
            << std::endl;
}

Accessing Subroutine Arguments

// Standard C++ requires that a function be prototyped, hence the name and type of parameters
// must be specified, and the argumemt list in any calls to that function must match the
// parameter list, as shown here 

#include <cmath>

double hypotenuse(double side1, double side2);

// ----

int main()
{
  double diag = hypotenuse(3.0, 4.0);
}

// ----

double hypotenuse(double side1, double side2)
{
  return std::sqrt(std::pow(side1, 2.0) + std::pow(side2, 2.0));
}

// ----------------------------

// Variable length argument list functions, via the C Language derived 'va_...' macros,
// are also supported. However use of this facility is particularly discouraged in C++
// because:
// * It is an inherently type-unsafe facility; type safety is a core C++ concern
// * Other facilities, such as overloaded functions, and default arguments [neither of which
//   are available in C] can sometimes obviate the need for variable length argument lists
// * OOP techniques can also lessen the need for variable length argument lists. The most
//   obvious example here is the Iostream library where repeated calls of I/O operators replace
//   the format string / variable arguments of 'printf'

#include <cmath>
#include <cstdarg>

double hypotenuse(double side1, ...);

// ----

int main()
{
  double diag = hypotenuse(3.0, 4.0);
}

// ----

double hypotenuse(double side1, ...)
{
  // More details available in the corresponding section of PLEAC-C/Posix/GNU
  va_list ap;
  va_start(ap, side1);
  double side2 = va_arg(ap, double);
  va_end(ap);

  return std::sqrt(std::pow(side1, 2.0) + std::pow(side2, 2.0));
}

// ----------------------------

// An example using default arguments appears below

#include <cmath>

// Specify default argument values in declaration
// Note: This may be done in either of the declaration or the definition [not both], but it
// makes more sense to do so in the declaration since these are usually placed in header files
// which may be included in several source files. The default argument values would need to be
// known in all those locations
double hypotenuse(double side1 = 3.0, double side2 = 4.0);

// ----

int main()
{
  // All arguments specified
  double diag = hypotenuse(3.0, 4.0);

  // Both calls utilise default argument value(s)
  diag = hypotenuse(3.0);

  diag = hypotenuse();
}

// ----

double hypotenuse(double side1, double side2)
{
  return std::sqrt(std::pow(side1, 2.0) + std::pow(side2, 2.0));
}

// ----------------------------

// A [very contrived, not very practical] example using function overloading appears below

#include <cmath>

double hypotenuse(double side1, double side2);
double hypotenuse(double side1);
double hypotenuse();

// ----

int main()
{
  // Call version (1)
  double diag = hypotenuse(3.0, 4.0);

  // Call version (2)
  diag = hypotenuse(3.0);

  // Call version (3)
  diag = hypotenuse();
}

// ----

// (1)
double hypotenuse(double side1, double side2)
{
  return std::sqrt(std::pow(side1, 2.0) + std::pow(side2, 2.0));
}

// (2)
double hypotenuse(double side1)
{
  return std::sqrt(std::pow(side1, 2.0) + std::pow(4.0, 2.0));
}

// (3)
double hypotenuse()
{
  return std::sqrt(std::pow(3.0, 2.0) + std::pow(4.0, 2.0));
}

// ----------------------------

#include <cstddef>
#include <vector>

std::vector<int> int_all(const double arr[], size_t arrsize);
std::vector<int> int_all(const std::vector<double>& arr);

// ----

int main()
{
  // Load vectors from built-in arrays, or use Boost 'assign' library
  const double nums[] = {1.4, 3.5, 6.7};
  const size_t arrsize = sizeof(nums) / sizeof(nums[0]);

  // Conversion effected at vector creation time
  std::vector<int> ints = int_all(nums, arrsize);

  // Vector -> vector copy / conversion 
  ints = int_all(std::vector<double>(nums, nums + arrsize));
}

// ----

std::vector<int> int_all(const double arr[], size_t arrsize)
{
  return std::vector<int>(arr, arr + arrsize);
}

std::vector<int> int_all(const std::vector<double>& arr)
{
  std::vector<int> r;
  r.assign(arr.begin(), arr.end());  // Type safe element copying 
  return r;
}

// ----------------------------

#include <algorithm>
#include <vector>

#include <cmath>
#include <cstddef>

void trunc_em(std::vector<double>& arr);

// ----

int main()
{
  // Load vectors from built-in arrays, or use Boost 'assign' library
  const double nums[] = {1.4, 3.5, 6.7};
  const size_t arrsize = sizeof(nums) / sizeof(nums[0]);

  std::vector<double> numsv(nums, nums + arrsize);

  trunc_em(numsv);
}

// ----

void trunc_em(std::vector<double>& arr)
{
  // Replace each element with the value returned by applying 'floor' to that element
  std::transform(arr.begin(), arr.end(), arr.begin(), floor);
}

Making Variables Private to a Function

// Variables declared within a function body are local to that function, and those declared
// outside a function body [and not as part of a class / struct definition, or enclosed within
// a namespace] are global, that is, are visible throughout the executable unless their
// visibility has been restricted to the source file in which they are defined via enclosing
// them within an anonymous namespace [which has the same effect as using the 'static' keyword,
// in this same context, in the C language]

#include <vector>

void somefunc()
{
  // All these variables are local to this function
  int variable, another;

  std::vector<int> vec(5);

  ; // ...
}

// ----------------------------

// A couple of generic, type-safe type conversion helpers. The Boost Library sports a conversion
// library at: http://www.boost.org/libs/conversion/index.html

#include <sstream>
#include <string>

class bad_conversion {};

template<typename T> T fromString(const std::string& s)
{
  std::istringstream iss(s);
  T t; iss >> t;
  if (!iss) throw bad_conversion();
  return t;
}

template<typename T> std::string toString(const T& t)
{
  std::ostringstream oss;
  oss << t << std::ends;
  if (!oss) throw bad_conversion();
  return std::string(oss.str());
}

// ------------

#include <string>

// File scope variables
namespace 
{
  std::string name;
  int age, c, condition;
}

void run_check();
void check_x(int x);

// ----

// An alternative, C++-specific approach, to command-line handling and type conversion
// may be seen at: http://www.boost.org/libs/conversion/lexical_cast.htm

int main(int argc, char* argv[])
{
  name.assign(argv[1]);

  try
  {  
    age = fromString<int>(argv[2]);
  }

  catch (const bad_conversion& e)
  {
    ; // ... handle conversion error ...
  }

  check_x(age);
}

// ------------

void run_check()
{
  // Full access to file scope variables
  condition = 1;
  // ...
}

void check_x(int x)
{
  // Full access to file scope variables
  std::string y("whatever");

  run_check();

  // 'condition' updated by 'run_check'
  if (condition)
  {
    ; // ...
  }
}

Creating Persistent Private Variables

// Standard C++, owing to its C heritage, allows the creation of 'persistent private variables',
// via use of the 'static' keyword. For more details about this, and illustrative code examples,
// refer to this same section in PLEAC-C/Posix/GNU. Standard C++-specific methods of perfoming
// this task involve use of the 'namespace' facility, or creating a class containing 'static'
// members and using access specifiers to restrict access

// This example replaces the 'static' keyword with use of an anonymous namespace to force
// 'variable' to have file scope, and be visible only within the 'mysubs.cpp file. It is
// therefore both persistant [because it is a global variable] and private [because it is
// visible only to functions defined within the same source file]

// File: 'mysubs.h'
void mysub(void);
void reset(void);

// ----

// File: 'mysubs.cpp'
namespace
{
  int variable = 1;
}

void mysub(void)
{
  ; // ... do something with 'variable' ...
}
 
void reset(void) { variable = 1; }

// ----

// File: 'test.cpp'
#include "mysubs.h"

int main()
{
  // 'variable' is not accessable here

  // Call 'mysub', which can access 'variable'
  mysub();

  // Call 'reset' which sets 'variable' to 1  
  reset();
}

// ------------

// This example is similar to the previous one in using an anonymous namespace to restrict
// variable visibility. It goes further, hoewever, grouping logically related items within
// a named namespace, thus ensuring access to those items is controlled [i.e. requires
// qualification, or a 'using' declaration or directive]

// File: 'counter.h'
namespace cnt
{
  int increment();
  int decrement();
}

// ----

// File: 'counter.cpp'
namespace cnt
{
  // Ensures 'counter' is visible only within the current source file
  namespace { int counter = 0; }

  void reset(int v = 0) { counter = v; }

  int increment() { return ++counter; }
  int decrement() { return --counter; }
}

// ----

// File: 'test.cpp'
#include <iostream>
#include "counter.h"

int main()
{
  // Following line is illegal because 'cnt::counter' is private to the 'counter.cpp' file
  // int c = cnt::counter;
  
  int a = cnt::increment();
  std::cout << a << std::endl;

  a = cnt::decrement();
  std::cout << a << std::endl;
}

// ------------

// This example sees a class containing 'static' members and using access specifiers to
// restrict access to those members. Since all the members are static, this class is not
// meant to be instantiated [i.e. objects created from it - it can be done, but they would
// all be the exact same object :)], but merely uses the 'class' facility to encapsulate
// [i.e. group together] and allow selective access [i.e. hide some parts, allow access to
// others]. For Design Pattern afficiandos, this is a crude example of the Singleton Pattern

// File: 'counter.h'
class Counter
{
public:
  static int increment();
  static int decrement();
private:
  static int counter;
};

// ----

// File: 'counter.cpp'
#include "counter.h"

int Counter::increment() { return ++counter; }
int Counter::decrement() { return --counter; }

int Counter::counter = 0;

// ----

// File: 'test.cpp'
#include <iostream>
#include "counter.h"

int main()
{
  int a = Counter::increment();
  std::cout << a << std::endl;

  a = Counter::decrement();
  std::cout << a << std::endl;
}

Determining Current Function Name

// Standard C++ offers no facility for performing adhoc, runtime stack inspection; therefore,
// information such as the currently-executing function name, cannot be obtained. Now, this
// isn't to say that such facilities don't exist [since, after all, a symbolic debugger works
// by doing just this - stack inspection, among other things], but that such features are, for
// native code compiled languages like C++, 'extra-language' and development tool-specific

Passing Arrays and Hashes by Reference

// Standard C++ supports both
// * 'pass-by-value': a copy of an argument is passed when calling a function; in this way
//   the original is safe from modification, but a copying overhead is incurred which may
//   adversely affect performance
// * 'pass-by-reference': the address of an argument is passed when calling a function;
//   allows the original to be modified, and incurrs no performance penalty from copying
//
// The 'pass-by-value' mechanism works in the same way as in the Standard C language [see
// corresponding section in PLEAC-C/Posix/GNU]. The 'pass-by-reference' mechanism provides
// the same functionality as passing a pointer-to-a-pointer-to-an-argument, but without the
// complications arising from having to correctly dereference. Using a reference to a non-const
// item allows:
// * The item's state to be modified i.e. if an object was passed, it can be mutated [effect
//   can be mimiced by passing a pointer to the item]
// * The item, itself, can be replaced with a new item i.e. the memory location to which the
//   reference refers is updated [effect can be mimiced by passing a pointer-to-a-pointer to
//   the item]

#include <cstddef>
#include <vector>

// 'pass-by-value': a copy of each vector is passed as an argument
// void array_diff(const std::vector<int> arr1, const std::vector<int> arr2);

// 'pass-by-reference': the address of each vector is passed as an argument. Some variants:
// * Disallow both vector replacement and alteration of its contents
//     void array_diff(const std::vector<const int>& arr1, const std::vector<const int>& arr2);
// * Disallow vector replacement only
//     void array_diff(const std::vector<int>& arr1, const std::vector<int>& arr2);
// * Disallow alteration of vector contents only
//     void array_diff(std::vector<const int>& arr1, std::vector<const int>& arr2);
// * Allow replacement / alteration
//     void array_diff(std::vector<int>& arr1, std::vector<int>& arr2);

void array_diff(const std::vector<int>& arr1, const std::vector<int>& arr2);

// ----

int main()
{
  // Load vectors from built-in arrays, or use Boost 'assign' library
  const int arr1[] = {1, 2, 3}, arr2[] = {4, 5, 6};
  const size_t arrsize = 3;

  // Function call is the same whether 'array_diff' is declared to be 'pass-by-value'
  // or 'pass-by-reference'
  array_diff(std::vector<int>(arr1, arr1 + arrsize), std::vector<int>(arr2, arr2 + arrsize));
}

// ----

// void array_diff(const std::vector<int> arr1, const std::vector<int> arr2)
// {
//  ; // 'arr1' and 'arr2' are copies of the originals
// }

void array_diff(const std::vector<int>& arr1, const std::vector<int>& arr2)
{
  ; // 'arr1' and 'arr2' are references to the originals
}

// ----------------------------

#include <cstddef>

#include <algorithm>
#include <functional>
#include <vector>

std::vector<int> add_vecpair(const std::vector<int>& arr1, const std::vector<int>& arr2);

// ----

int main()
{
  // Load vectors from built-in arrays, or use Boost 'assign' library
  const int aa[] = {1, 2}, ba[] = {5, 8};
  size_t arrsize = 2;

  const std::vector<int> a(aa, aa + arrsize), b(ba, ba + arrsize);  

  std::vector<int> c = add_vecpair(a, b);
}

// ----

std::vector<int> add_vecpair(const std::vector<int>& arr1, const std::vector<int>& arr2)
{
  std::vector<int> retvec; retvec.reserve(arr1.size());
  std::transform(arr1.begin(), arr1.end(), arr2.begin(), back_inserter(retvec), std::plus<int>());
  return retvec;
}

Detecting Return Context

// Please refer to the corresponding section in PLEAC-C/Posix/GNU since the points raised there
// apply to C++ also. Examples here don't so much illustrate C++'s handling of 'return context'
// as much as how disparate types might be handled in a reasonably uniform manner

// Here, 'mysub' is implemented as a function template, and its return type varies with the
// argument type. In most cases the compiler is able to infer the return type from the 
// argument, however, it is possible to pass the type as a template parameter. Note this
// code operates at compile-time, as does any template-only code

#include <cstddef>

#include <string>
#include <vector>

template <typename T> T mysub(const T& t) { return t; }

// ----

int main()
{
  // 1. Type information inferred by compiler
  int i = mysub(5);

  double d = mysub(7.6);

  const int arr[] = {1, 2, 3};
  const size_t arrsize = sizeof(arr) / sizeof(arr[0]);

  std::vector<int> v = mysub(std::vector<int>(arr, arr + arrsize));

  // 2. Type information provided by user
  // Pass a 'const char*' argument and specify type information in the call
  std::string s = mysub<std::string>("xyz");

  // Could avoid specifying type information by passing a 'std::string' argument  
  // std::string s = mysub(std::string("xyz"));
}

// ----------------------------

// This is a variant on the previous example that uses the Boost Library's 'any' type as a
// generic 'stub' type

#include <string>
#include <vector>

#include <boost/any.hpp>

template <typename T> boost::any mysub(const T& t) { return boost::any(t); }

// ----

int main()
{
  std::vector<boost::any> any;

  // Add various types [encapsulated in 'any' objects] to the container
  any.push_back(mysub(5));
  any.push_back(mysub(7.6));
  any.push_back(mysub(std::vector<int>(5, 5)));
  any.push_back(mysub(std::string("xyz")));

  // Extract the various types from the container by appropriately casting the relevant
  // 'any' object
  int i = boost::any_cast<int>(any[0]);
  double d = boost::any_cast<double>(any[1]);
  std::vector<int> v = boost::any_cast< std::vector<int> >(any[2]);
  std::string s = boost::any_cast<std::string>(any[3]);
}

Passing by Named Parameter

// Just like the C language, C++ offers no support for named / keyword parameters. It is of
// course possible to mimic such functionality the same way it is done in C [see corresponding
// section in PLEAC-C/Posix/GNU], the most obvious means being by passing a set of key/value
// pairs in a std::map. This will not be shown here. Instead, two quite C++-specific examples
// will be provided, based on:
//
// * Named Parameter Idiom [see: http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.18]
// * Boost 'parameter' Library [see: http://www.boost.org/libs/parameter/doc/html/index.html]

#include <iostream>
#include <map>

class TimeEntry
{
public:
  explicit TimeEntry(int value = 0, char dim = 's');

  bool operator<(const TimeEntry& right) const;

  friend std::ostream& operator<<(std::ostream& out, const TimeEntry& t);

private:
  int value_;
  char dim_;
};

typedef std::pair<const int, TimeEntry> TENTRY;
typedef std::map<const int, TimeEntry> TIMETBL;

class RaceTime
{
public:
  const static int START_TIME, FINISH_TIME, INCR_TIME;

public:
  explicit RaceTime();

  RaceTime& start_time(const TimeEntry& time);
  RaceTime& finish_time(const TimeEntry& time);
  RaceTime& incr_time(const TimeEntry& time);

  friend std::ostream& operator<<(std::ostream& out, const RaceTime& r);

private:
  TIMETBL timetbl_;
};

const int RaceTime::START_TIME = 0, RaceTime::FINISH_TIME = 1, RaceTime::INCR_TIME = 2;

void the_func(const RaceTime& r);

// ----

int main()
{
  the_func(RaceTime().start_time(TimeEntry(20, 's')).finish_time(TimeEntry(5, 'm')).incr_time(TimeEntry(5, 's')));

  the_func(RaceTime().start_time(TimeEntry(5, 'm')).finish_time(TimeEntry(30, 'm')));

  the_func(RaceTime().start_time(TimeEntry(30, 'm')));
}

// ----

std::ostream& operator<<(std::ostream& out, const TimeEntry& t)
{
  out << t.value_ << t.dim_; return out;
}

std::ostream& operator<<(std::ostream& out, const RaceTime& r)
{
  RaceTime& r_ = const_cast<RaceTime&>(r);

  out << "start_time:  " << r_.timetbl_[RaceTime::START_TIME]
      << "\nfinish_time: " << r_.timetbl_[RaceTime::FINISH_TIME]
      << "\nincr_time:   " << r_.timetbl_[RaceTime::INCR_TIME];

  return out;
}

TimeEntry::TimeEntry(int value, char dim) : value_(value), dim_(dim) {}

bool TimeEntry::operator<(const TimeEntry& right) const
{
  return (dim_ == right.dim_) ? (value_ < right.value_) : !(dim_ < right.dim_);
}

RaceTime::RaceTime()
{
  timetbl_.insert(TENTRY(START_TIME, TimeEntry(0, 's')));
  timetbl_.insert(TENTRY(FINISH_TIME, TimeEntry(0, 's')));
  timetbl_.insert(TENTRY(INCR_TIME, TimeEntry(0, 's')));
}

RaceTime& RaceTime::start_time(const TimeEntry& time)
{
  timetbl_[START_TIME] = time; return *this;
}

RaceTime& RaceTime::finish_time(const TimeEntry& time)
{
  timetbl_[FINISH_TIME] = time; return *this;
}

RaceTime& RaceTime::incr_time(const TimeEntry& time)
{
  timetbl_[INCR_TIME] = time; return *this;
}

void the_func(const RaceTime& r)
{
  std::cout << r << std::endl;
}

// ----------------------------

// The Boost 'parameter' library requires a significant amount of setup code to be written,
// much more than this section warrants. My recommendation is to read carefully through the
// tutorial to determine whether a problem for which it is being considered justifies all
// the setup.

Skipping Selected Return Values

// The Boost 'tuple' Library also allows multiple assignment to variables, including the
// selective skipping of return values

#include <iostream>

#include <boost/tuple/tuple.hpp>

typedef boost::tuple<int, int, int> T3;

T3 func();

// ----

int main()
{
  int a = 6, b = 7, c = 8;
  std::cout << a << ',' << b << ',' << c << std::endl;

  // A tuple of references to the referred variables is created; the values
  // captured from the returned tuple are thus multiply-assigned to them
  boost::tie(a, b, c) = func();
  std::cout << a << ',' << b << ',' << c << std::endl;

  // Variables can still be individually referenced
  a = 11; b = 23; c = 56; 
  std::cout << a << ',' << b << ',' << c << std::endl;

  // Return values may be ignored; affected variables retain existing values
  boost::tie(a, boost::tuples::ignore, c) = func();
  std::cout << a << ',' << b << ',' << c << std::endl;
}

// ----

T3 func() { return T3(3, 6, 9); }

Returning More Than One Array or Hash

// Like Standard C, C++ allows only the return of a single value. The return of multiple values
// *can*, however, be simulated by packaging them within an aggregate type [as in C], or a
// custom class, or one of the STL containers like std::vector. Probably the most robust, and
// [pseudo]-standardised, approach is to use the Boost 'tuple' Library, as will be done in this
// section. Notes:
// * Use made of Boost 'assign' Library to simplify container loading; this is a *very* handy
//   library
// * Use made of Boost 'any' Library to make containers heterogenous; 'variant' Library is
//   similar, and is more appropriate where type-safe container traversal is envisaged e.g.
//   for printing  

#include <string>
#include <vector>
#include <map>

#include <boost/any.hpp>
#include <boost/tuple/tuple.hpp>

#include <boost/assign/std/vector.hpp>
#include <boost/assign/list_inserter.hpp>

typedef std::vector<boost::any> ARRAY;
typedef std::map<std::string, boost::any> HASH;
typedef boost::tuple<ARRAY, HASH> ARRAY_HASH;

ARRAY_HASH some_func(const ARRAY& array, const HASH& hash);

// ----

int main()
{
  // Load containers using Boost 'assign' Library 
  using namespace boost::assign;
  ARRAY array; array += 1, 2, 3, 4, 5;
  HASH hash; insert(hash) ("k1", 1) ("k2", 2) ("k3", 3);

  // Pass arguments to 'somefunc' and retrieve them as members of a tuple
  ARRAY_HASH refs = some_func(array, hash);

  // Retrieve copy of 'array' from tuple
  ARRAY ret_array = boost::get<0>(refs);

  // Retrieve copy of 'hash' from tuple
  HASH ret_hash = boost::get<1>(refs);
}

// ----

ARRAY_HASH some_func(const ARRAY& array, const HASH& hash)
{
  ; // ... do something with 'array' and 'hash'

  return ARRAY_HASH(array, hash);
}

Returning Failure

// Like function calls in Standard C, function calls in C++ need to conform to signature
// requirements; a function call must match its declaration with the same number, and type,
// of arguments passed [includes implicitly-passed default arguments], and the same return
// value type. Thus, unlike Perl, a function declared to return a value *must* do so, thus
// cannot 'return nothing' to indicate failure. 
// Whilst in Standard C certain conventions like returning NULL pointers, or returning -1, to
// indicate the 'failure' of a task [i.e. function return codes are checked, and control
// proceeds conditionally] are used, Standard C++ sports facilities which lessen the need for
// dong the same. Specifically, C++ offers:
// * Built-in exception handling which can be used to detect [and perhaps recover from],
//   all manner of unusual, or erroneous / problematic situations. One recommended use is
//   to avoid writing code that performs a lot of return code checking
// * Native OOP support allows use of the Null Object Design Pattern. Put simply, rather than
//   than checking return codes then deciding on an action, an object with some predefined
//   default behaviour is returned / used where an unusual / erroneous / problematic situation
//   is encountered. This approach could be as simple as having some sort of default base
//   class member function behaviour, or as complex as having a diagnostic-laden object created
// * Functions can still return 'error-indicating entities', but rather than primitive types
//   like 'int's or NULL pointers, complex objects can be returned. For example, the Boost
//   Library sports a number of such types:
//   - 'tuple'
//   - 'any', 'variant' and 'optional'
//   - 'tribool' [true, false, indeterminate]

// Exception Handling Example

class XYZ_exception {};

int func();

// ----

int main()
{
  int valid_value = 0;

  try
  {
    ; // ...

    valid_value = func();

    ; // ...
  }

  catch(const XYZ_exception& e)
  {
    ; // ...
  }
}

// ----

int func()
{
  bool error_detected = false;
  int valid_value;

  ; // ...

  if (error_detected) throw XYZ_exception();

  ; // ...
  
  return valid_value;
}

// ------------

// Null Object Design Pattern Example

#include <iostream>

class Value
{
public:
  virtual void do_something() = 0;
};

class NullValue : public Value
{
public:
  virtual void do_something();
};

class ValidValue : public Value
{
public:
  virtual void do_something();
};

Value* func();

// ----

int main()
{
  // Error checking is performed within 'func'. However, regardless of the outcome, an
  // object of 'Value' type is returned which possesses similar behaviour, though appropriate
  // to whether processing was successful or not. In this way no error checking is needed
  // outside of 'func'
  Value* v = func();

  v->do_something();

  delete v;
}

// ----

void NullValue::do_something()
{
  std::cout << "*null*" << std::endl;
}

void ValidValue::do_something()
{
  std::cout << "valid" << std::endl;
}

Value* func()
{
  bool error_detected = true;

  ; // ...

  if (error_detected) return new NullValue;

  ; // ...
  
  return new ValidValue;
}

// ----------------------------

// The Boost 'optional' library has many uses, but in the current context, one is of particular
// use: returning a specified type [thus satisfying language requirements], but whose value
// may be 'set' [if the function succeeded] or 'unset' [if it failed], and this condition very
// easily checked

#include <iostream>

#include <cstdlib>

#include <string>
#include <vector>
#include <map>

#include <boost/optional/optional.hpp>

class func_fail
{
public:
  explicit func_fail(const std::string& msg) : msg_(msg) {}
  const std::string& msg() const { return msg_; } 
private:
  const std::string msg_;
};

// ----

void die(const std::string& msg);

boost::optional<int> sfunc();
boost::optional< std::vector<int> > afunc();
boost::optional< std::map<std::string, int> > hfunc();

// ------------

int main()
{
  try
  {
    boost::optional<int> s;
    boost::optional< std::vector<int> > a;
    boost::optional< std::map<std::string, int> > h;

    if (!(s = sfunc())) throw func_fail("'sfunc' failed");
    if (!(a = afunc())) throw func_fail("'afunc' failed");
    if (!(h = hfunc())) throw func_fail("'hfunc' failed");

    ; // ... do stuff with 's', 'a', and 'h' ...
    int scalar = *s;

    ; // ...
  }

  catch (const func_fail& e)
  {
    die(e.msg());   
  }

  ; // ... other code executed if no error above ...
}

// ------------

void die(const std::string& msg)
{
  std::cerr << msg << std::endl;

  // Should only be used if all objects in the originating local scope have been destroyed
  std::exit(EXIT_FAILURE);
}

// ----

boost::optional<int> sfunc()
{
  bool error_detected = true;

  int valid_int_value;

  ; // ...

  if (error_detected) return boost::optional<int>();

  ; // ...
  
  return boost::optional<int>(valid_int_value);
}

boost::optional< std::vector<int> > afunc()
{
  // ... code not shown ...
 
  return boost::optional< std::vector<int> >();

  // ... code not shown
}

boost::optional< std::map<std::string, int> > hfunc()
{
  // ... code not shown ...

  return boost::optional< std::map<std::string, int> >();

  // ... code not shown ...
}

Prototyping Functions

// Whilst in Perl function prototyping is optional, this is not the case in C++, where it is
// necessary to:
// * Declare a function before use; this could either be a function declaration separate from
//   the function definition, or the function definition itself which serves as its own
//   declaration
// * Specify both parameter positional and type information; parameter names are optional in
//   declarations, mandatory in definitions
// * Specify return type

#include <iostream>
#include <vector>

// Function Declaration
std::vector<int> myfunc(int arg1, int arg2); // Also possible: std::vector<int> myfunc(int, int);

// ----

int main()
{
  // Call function with all required arguments; this is the only calling method
  // [except for calling via function pointer which still needs all arguments supplied]
  std::vector<int> results = myfunc(3, 5);

  // Let's look at our return array's contents
  std::cout << results[0] << ':' << results[1] << std::endl;
}

// ----

// Function Definition
std::vector<int> myfunc(int arg1, int arg2)
{
  std::vector<int> r;

  std::back_inserter(r) = arg1;
  std::back_inserter(r) = arg2;

  return r;
}

// ------------

// A version on the above code that is generic, that is, making use of the C++ template
// mechanism to work with any type

#include <iostream>
#include <vector>

// Function Declaration
template <class T> std::vector<T> myfunc(const T& arg1, const T& arg2);

// ----

int main()
{
  std::vector<int> results = myfunc(3, 5);

  std::cout << results[0] << ':' << results[1] << std::endl;
}

// ----

// Function Definition
template <class T> std::vector<T> myfunc(const T& arg1, const T& arg2)
{
  std::vector<T> r;

  std::back_inserter(r) = arg1;
  std::back_inserter(r) = arg2;

  return r;
}

// ------------

// Other Perl examples are omitted since there is no variation in C++ function calling or
// parameter handling

Handling Exceptions

// One of the key, non-object oriented features of Standard C++ is its built-in support for
// exceptions / exception handling. The feature is well-integrated into the language, including
// a set of predefined exception classes included in, and used by, the Standard Library, is
// quite easy to use, and helps the programmer write robust code provided certain conventions
// are followed. On the downside, the C++ exception handling system is criticised for imposing
// significant runtime overhead, as well as increasing executable code size [though this
// varies considerably between CPU's, OS's, and compilers]. Please refer to the corresponding
// section in PLEAC-C/Posix/GNU for pertinent reading references.
//
// The example code below matches the PLEAC-C/Posix/GNU example rather than the Perl code. Note:
// * A very minimal, custom exception class is implemented; a more complex class, one richer in
//   diagnostic information, could have been implemented, or perhaps one based on a standard
//   exception class like 'std::exception'
// * Ordinarily error / exception messages are directed to 'std::cerr' or 'std::clog'
// * General recommendation is to throw 'temporaries' [via invoking a constructor],
//   and to 'catch' as const reference(s)
// * Proper 'cleanup' is very important; consult a suitable book for guidance on writing
//   'exception safe' code

#include <iostream>
#include <string>

class FullmoonException
{
public:
  explicit FullmoonException(const std::string& msg) : msg_(msg) {}

  friend std::ostream& operator<<(std::ostream& out, const FullmoonException& e)
  {
    out << e.msg_; return out;
  }
private:
  const std::string msg_;
};

// ----

int main()
{
  std::cout << "main - entry" << std::endl;

  try
  {
    std::cout << "try block - entry" << std::endl;
    std::cout << "... doing stuff ..." << std::endl;

    // if (... error condition detected ...)
         throw FullmoonException("... the problem description ...");

    // Control never gets here ...
    std::cout << "try block - end" << std::endl;
  }

  catch(const FullmoonException& e)
  {
    std::cout << "Caught a'Fullmoon' exception. Message: "
              << "[" << e << "]"
              << std::endl;
  }

  catch(...)
  {
    std::cout << "Caught an unknown exceptione" << std::endl;
  }

  // Control gets here regardless of whether an exception is thrown or not
  std::cout << "main - end" << std::endl;
}

Saving Global Values

// Standard C++ sports a namespace facility which allows an application to be divided into
// logical sub-systems, each of which operates within its own scope. Put very simply, the same
// identifiers [i.e. name of types, objects, and functions] may be each used in a namespace
// without fear of a nameclash occurring when logical sub-systems are variously combined as
// an application. The name-clash problem is inherent in single-namespace languages like C; it
// often occurs when several third-party libraries are used [a common occurrence in C], or
// when an application scales up. The remedy is to rename identifiers, or, in the case of 
// functions that cannot be renamed, to wrap them up in other functions in a separate source
// file. Of course the problem may be minimised via strict adherence to naming conventions. 
//
// The C++ namespace facility is important, too, because it avoids the need to utilise certain
// C language practices, in particular:
// * Use of, possibly, 'clumsy' naming conventions [as described above]
// * Partition an application by separating logically-related items into separate source
//   files. Namespaces cross file boundaries, so items may reside in several source files
//   and still comprise a single, logical sub-system
// * Anonymous namespaces avoid use of the 'static' keyword in creating file scope globals

// Global variable
int age = 18;

// ----

void print_age()
{
  // Global value, 'age', is accessed
  std::cout << "Age is " << age << std::endl;
}

// ------------

int main()
{
  // A local variable named, 'age' will act to 'shadow' the globally
  // defined version, thus any changes to, 'age', will not affect
  // the global version
  int age = 5;

  // Prints 18, the current value of the global version
  print_age();

  // Local version is altered, *not* global version
  age = 23;

  // Prints 18, the current value of the global version
  print_age();
}

// ----------------------------

// Global variable
int age = 18;

// ----

void print_age()
{
  // Global value, 'age', is accessed
  std::cout << "Age is " << age << std::endl;
}

// ------------

int main()
{
  // Here no local version declared: any changes affect global version
  age = 5;

  // Prints 5, the new value of the global version
  print_age();

  // Global version again altered
  age = 23;

  // Prints 23, the new value of the global version
  print_age();
}

// ----------------------------

// Global variable
int age = 18;

// ----

void print_age()
{
  // Global value, 'age', is accessed
  std::cout << "Age is " << age << std::endl;
}

// ------------

int main()
{
  // Global version value saved into local version
  int age = ::age;

  // Prints 18, the new value of the global version
  print_age();

  // Global version this time altered
  ::age = 23;

  // Prints 23, the new value of the global version
  print_age();

  // Global version value restored from saved local version
  ::age = age;

  // Prints 18, the restored value of the global version
  print_age();
}

Redefining a Function

// Please refer to the corresponding section in PLEAC-C/Posix/GNU since the points raised there
// about functions and function pointers apply equally to Standard C++ [briefly: functions
// cannot be redefined; several same-signature functions may be called via the same function
// pointer variable; code cannot be generated 'on-the-fly' (well, not without the use of
// several external tools, making it an extra-language, not integral, feature)].
// @@INCOMPLETE@@

Trapping Undefined Function Calls with AUTOLOAD

// Please refer to the corresponding section in PLEAC-C/Posix/GNU since all the points raised
// there apply equally to Standard C++ [briefly: undefined function calls are compiler-detected
// errors; function-pointer-based calls can't be checked for integrity].
// @@INCOMPLETE@@

Nesting Subroutines

// Standard C++ does not support either simple nested functions or closures, therefore the
// example cannot be implemented exactly as per the Perl code

/* ===
int outer(int arg)
{
  int x = arg + 35;

  // *** wrong - illegal C++ ***
  int inner() { return x * 19; }

  return x + inner();
}
=== */

// The problem may, of course, be solved by defining two functions using parameter passing
// where appropriate, but this is contrary to the intent of the original Perl code
int inner(int x)
{
  return x * 19;
}

int outer(int arg)
{
  int x = arg + 35;
  return x + inner(x);
}

// An arguably better [but far more complicated] approach is to encapsulate all items within
// a namespace, but again, is an approach that is counter the intent of the original Perl code
#include <iostream>

namespace nst
{
  int x;
  int inner();
  int outer(int arg);
}

// ----

int main()
{
  std::cout << nst::outer(3) << std::endl;
}

// ----

int nst::inner()
{
  return nst::x * 19;
}

int nst::outer(int arg)
{
  nst::x = arg + 35;
  return nst::x + nst::inner();
}

// Another way to solve this problem and avoiding the use of an external function, is to
// create a local type and instantiate an object passing any required environment context
// to the constructor. Then, what appears as a parameterless nested function call, can be
// effected using 'operator()'. This approach most closely matches the original Perl code

int outer(int arg)
{
  int x = arg + 35;

  // 'Inner' is what is known as a Functor or Function Object [or Command Design Pattern]; it
  // allows objects that capture state / context to be instantiated, and that state / context
  // used / retained / altered at multiple future times. Both the STL and Boost Libraries
  // provide extensive support these constructs
  struct Inner
  {
    int n_;
    explicit Inner(int n) : n_(n) {}
    int operator()() const { return n_ * 19; }
  } inner(x);

  return x + inner();
}

Program: Sorting Your Mail

// @@INCOMPLETE@@
// @@INCOMPLETE@@