From 200144dd009d33ff8334be24d0fb2cc91b3a87ab Mon Sep 17 00:00:00 2001 From: murphy Date: Wed, 14 Apr 2010 23:59:03 +0000 Subject: Moving scanner tests into separate repository. The repository can be reached at http://svn.rubychan.de/coderay-scanner-tests/trunk. --- test/scanners/cpp/pleac.in.cpp | 2041 ---------------------------------------- 1 file changed, 2041 deletions(-) delete mode 100644 test/scanners/cpp/pleac.in.cpp (limited to 'test/scanners/cpp/pleac.in.cpp') diff --git a/test/scanners/cpp/pleac.in.cpp b/test/scanners/cpp/pleac.in.cpp deleted file mode 100644 index 5a09e8c..0000000 --- a/test/scanners/cpp/pleac.in.cpp +++ /dev/null @@ -1,2041 +0,0 @@ -// -*- c++ -*- - -// @@PLEAC@@_NAME -// @@SKIP@@ C++/STL/Boost - - -// @@PLEAC@@_WEB -// @@SKIP@@ http://www.research.att.com/~bs/C++.html -// @@SKIP@@ http://www.boost.org/ - - -// @@PLEAC@@_1.0 -// 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. - -// In C++, one can use the builtin 'char *' type or the 'string' type -// to represent strings. In this section, we will work with the C++ -// library 'string' class. - -// Characteristics of 'string' types: -// - may be of any length -// - are defined within the std namespace -// - can be converted to a 'const char *' using std::string::c_str() -// - can be subscripted to access individual characters (e.g., str[3] -// returns the 4th character of the string -// - memory associated with strings is reclaimed automatically as strings -// go out of scope -// - strings cannot be used as true/false values (i.e., the following is not -// allowed: string s; if (s) {}) - -//----------------------------- -// Before using strings, you must include the header file -#include - -//----------------------------- -// To create a literal strings, you must use double quotes ("). You cannot -// use single quotes. - -//----------------------------- -// String variables must be declared -- if no value is given it's -// value is the empty string (""). -std::string s; - -//----------------------------- -// To insert special characters, quote the character with \ -std::string s1 = "\\n"; // Two characters, \ and n -std::string s2 = "Jon \"Maddog\" Orwant"; // Literal double quotes - -//----------------------------- -// Strings can be declared in one of two ways -std::string s1 = "assignment syntax"; -std::string s2("constructor syntax"); - -//----------------------------- -// Multi-line strings. -// There is no equivalent to perl's "here" documents in c++ -std::string s1 = " -This is a multiline string started and finished with double -quotes that spans 4 lines (it contains 3 newline characters). -"; - -std::string s2 = "This is a multiline string started and finished with double -quotes that spans 2 lines (it contains 1 newline character)."; -//----------------------------- - - -// @@PLEAC@@_1.1 -std::string s = "some string"; - -//----------------------------- -std::string value1 = s.substr(offset, length); -std::string value2 = s.substr(offset); - -// Unlike perl, the substr function returns a copy of the substring -// rather than a reference to the existing substring, thus using substr -// on the left hand side of an assignment statement will not modify -// the original string. To get this functionality, you can use the -// std::string::replace function. - -// Using offsets and lengths -s.replace(offset, length, newstring); -s.replace(offset, s.size()-offset, newtail); - -//----------------------------- -// The C++ string class doesn't have anything equivalent to perl's unpack. -// Instead, one can use C structures to import/export binary data - -//----------------------------- -#include -string s = "This is what you have"; - -std::string first = s.substr(0, 1); // "T" -std::string second = s.substr(5, 2); // "is" -std::string rest = s.substr(13); // "you have" - -// C++ strings do not support backwards indexing as perl does but -// you can fake it out by subtracting the negative index from the -// string length -std::string last = s.substr(s.size()-1); // "e" -std::string end = s.substr(s.size()-4); // "have" -std::string piece = s.substr(s.size()-8, 3); // "you" - -//----------------------------- -#include -#include - -string s("This is what you have"); -std::cout << s << std::endl; -// This is what you have - -s.replace(5,2,"wasn't"); // change "is to "wasn't" -// This wasn't what you have - -s.replace(s.size()-12, 12, "ondrous"); // "This wasn't wondrous" -// This wasn't wonderous - -s.replace(0, 1, ""); // delete first character -// his wasn't wondrous - -s.replace(s.size()-10, 10, ""); // delete last 10 characters -// his wasn' - -//----------------------------- -// C++ does not have built-in support for the perl s///, m//, and tr/// -// operators; however, similar results can be achieved in at least -// two ways: -// - string operations such as string::find, string::rfind, etc. -// - the boost regular expression library (regex++) supports perl -// regular expression syntax. -// TODO: Add examples of each. - -// MISSING: if (substr($string, -10) =~ /pattern/) { -// print "Pattern matches in last 10 characters\n"; -// } - -// MISSING: substr($string, 0, 5) =~ s/is/at/g; - -//----------------------------- -// exchange the first and last letters in a string using substr and replace -string a = "make a hat"; - -std::string first = a.substr(0,1); -std::string last = a.substr(a.size()-1); - -a.replace(0,1, last); -a.replace(a.size()-1, 1, first); - -// exchange the first and last letters in a string using indexing and swap -#include -std::swap(a[0], a[a.size()-1]); -//----------------------------- - - -// @@PLEAC@@_1.2 -//----------------------------- -// C++ doesn't have functionality equivalent to the || and ||=. -// If statements and trigraphs can be used instead. -//----------------------------- -// C++ doesn't have anything equivalent "defined". C++ variables -// cannot be used at all if they have not previously been defined. - -//----------------------------- -// Use b if b is not empty, else c -a = b.size() ? b : c; - -// Set x to y unless x is not empty -if (x.is_empty()) x = y; - -//----------------------------- -foo = (!bar.is_empty()) ? bar : "DEFAULT VALUE"; - -//----------------------------- -// NOTE: argv is declared as char *argv[] in C/C++. We assume -// the following code surrounds the following examples that deal -// with argv. Also, arguments to a program start at argv[1] -- argv[0] -// is the name of the executable that's running. -#include -int main(int argc, char *argv[]) { - char **args = argv+1; // +1 skips argv[0], the name of the executable - // examples -} - -//----------------------------- -std::string dir = (*args) ? *argv++ : "/tmp"; - -//----------------------------- -std::string dir = argv[1] ? argv[1] : "/tmp"; - -//----------------------------- -std::string dir = (argc-1) ? argv[1] : "/tmp"; - -//----------------------------- -#include -std::map count; - -count[shell.size() ? shell : "/bin/sh"]++; - -//----------------------------- -// find the user name on Unix systems -// TODO: Simplify. This is too ugly and complex -#include -#include -#include -#include "boost/lexical_cast.hpp" - -std::string user; -char *msg = 0; -passwd *pwd = 0; - -if ( (msg = getenv("USER")) || - (msg = getenv("LOGNAME")) || - (msg = getlogin()) ) - user = msg; -else if (pwd = getpwuid(getuid())) - user = pwd->pw_name; -else - user = "Unknown uid number " + boost::lexical_cast(getuid()); - -//----------------------------- -if (starting_point.is_empty()) starting_point = "Greenwich"; - -//----------------------------- -// Example using list. Other C++ STL containers work similarly. -#include -list a, b; -if (a.is_empty()) a = b; // copy only if a is empty -a = (!b.is_empty()) ? b : c; // asign b if b nonempty, else c -//----------------------------- - - -// @@PLEAC@@_1.3 -//----------------------------- -#include -std::swap(a, b); - -//----------------------------- -temp = a; -a = b; -b = temp; - -//----------------------------- -std::string a("alpha"); -std::string b("omega"); -std::swap(a,b); - -//----------------------------- -// The ability to exchange more than two variables at once is not -// built into the C++ language or C++ standard libraries. However, you -// can use the boost tuple library to accomplish this. -#include - -boost::tie(alpha,beta,production) - = boost::make_tuple("January", "March", "August"); -// move beta to alpha, -// move production to beta, -// move alpha to production -boost::tie(alpha, beta, production) - = boost::make_tuple(beta, production, alpha); -//----------------------------- - - -// @@PLEAC@@_1.4 -//----------------------------- -// There are several ways to convert between characters -// and integers. The examples assume the following declarations: -char ch; -int num; - -//----------------------------- -// Using implicit conversion -num = ch; -ch = num; - -//----------------------------- -// New-style C++ casts -ch = static_cast(num); -num = static_cast(ch); - -//----------------------------- -// Old-style C casts -ch = (char)num; -num = (int)ch; - -//----------------------------- -// Using the C++ stringstream class -#include // On some older compilers, use -std::stringstream a; // On some older compilers, use std::strstream - -a << ch; // Append character to a string -a >> num; // Output character as a number - -a << num; // Append number to a string -a >> ch; // Output number as a character - -//----------------------------- -// Using sprintf, printf -char str[2]; // Has to be length 2 to have room for NULL character -sprintf(str, "%c", num); -printf("Number %d is character %c\n", num, num); - -//----------------------------- -int ascii_value = 'e'; // now 101 -char character = 101; // now 'e' - -//----------------------------- -printf("Number %d is character %c\n", 101, 101); - -//----------------------------- -// Convert from HAL to IBM, character by character -#include -#include - -std::string ibm, hal = "HAL"; -for (unsigned int i=0; i -#include -#include // For bind1st and plus<> -#include // For transform - -std::string hal = "HAL"; -transform(hal.begin(), hal.end(), hal.begin(), - bind1st(plus(),1)); -std::cout << hal << std::endl; // prints "IBM" -//----------------------------- - - -// @@PLEAC@@_1.5 -//----------------------------- -// Since C++ strings can be accessed one character at a time, -// there's no need to do any processing on the string to convert -// it into an array of characters. -#include -std::string s; - -// Accessing characters using for loop and integer offsets -for (unsigned int i=0; i seen; - -for (std::string::iterator i=str.begin(); i!=str.end(); ++i) - seen[*i]++; - -std::cout << "unique chars are: "; -for (std::map::iterator i=seen.begin(); i!=seen.end(); ++i) - std::cout << i->first; -std::cout << std::endl; -// unique chars are: adelnpy - -//----------------------------- -int sum = 0; -for (std::string::iterator i=str.begin(); i!=str.end(); ++i) - sum += *i; -std::cout << "sum is " << sum << std::endl; -// prints "sum is 1248" if str was "an appla a day" - - -//----------------------------- -// MISSING: sysv-like checksum program - -//----------------------------- -// slowcat, emulate a slow line printer -#include -#include -#include - -int main(int argc, char *argv[]) { - timeval delay = { 0, 50000 }; // Delay in { seconds, nanoseconds } - char **arg = argv+1; - while (*arg) { // For each file - std::ifstream file(*arg++); - char c; - while (file.get(c)) { - std::cout.put(c); - std::cout.flush(); - select(0, 0, 0, 0, &delay); - } - } -} -//----------------------------- - - -// @@PLEAC@@_1.6 -//----------------------------- -#include -#include // For reverse -std::string s; - -reverse(s.begin(), s.end()); - -//----------------------------- -#include // For std::vector -#include // On older compilers, use -#include "boost/regex.hpp" // For boost::regex_split - -std::string str; -std::vector words; -boost::regex_split(std::back_inserter(words), str); -reverse(words.begin(), words.end()); // Reverse the order of the words - -std::stringstream revwords; // On older compilers, use strstream -copy(words.begin(), words.end(), ostream_inserter(revwords," "); -std::cout << revwards.str() << std::endl; - -//----------------------------- -std::string rts = str; -reverse(rts.begin(), rts.end()); // Reverses letters in rts - -//----------------------------- -std::vector words; -reverse(words.begin(), words.end()); // Reverses words in container - -//----------------------------- -// Reverse word order -std::string s = "Yoda said, 'can you see this?'"; - -std::vector allwords; -boost::regex_split(std::back_inserter(allwords), s); - -reverse(allwords.begin(), allwords.end()); - -std::stringstream revwords; // On older compilers, use strstream -copy(allwords.begin(), allwords.end(), ostream_inserter(revwords," ")); -std::cout << revwards.str() << std::endl; -// this?' see you 'can said, Yoda - -//----------------------------- -std::string word = "reviver"; -bool is_palindrome = equal(word.begin(), word.end(), word.rbegin()); - -//----------------------------- -#include - -std::ifstream dict("/usr/dict/words"); -std::string word; -while(getline(dict,word)) { - if (equal(word.begin(), word.end(), word.rbegin()) && - word.size() > 5) - std::cout << word << std::endl; -} -//----------------------------- - - -// @@PLEAC@@_1.7 -//----------------------------- -#include - -std::string::size_type pos; -while ((pos = str.find("\t")) != std::string::npos) - str.replace(pos, 1, string(' ',8-pos%8)); -//----------------------------- - - -// @@PLEAC@@_1.8 -//----------------------------- -// Not applicable to C++ -//----------------------------- - - -// @@PLEAC@@_1.9 -//----------------------------- -// TODO: Fix to be more like cookbook -// TODO: Modify/add code to do this with locales -#include -#include - -std::string phrase = "bo peep"; -transform(phrase.begin(), phrase.end(), phrase.begin(), toupper); -// "BO PEEP" -transform(phrase.begin(), phrase.end(), phrase.begin(), tolower); -// "bo peep" -//----------------------------- - - -// @@PLEAC@@_1.10 -//----------------------------- -// C++ does not provide support for perl-like in-string interpolation, -// concatenation must be used instead. - -#include - -std::string var1, var2; -std::string answer = var1 + func() + var2; // func returns string or char * - -//----------------------------- -#include "boost/lexical_cast.hpp" - -int n = 4; -std::string phrase = "I have " + boost::lexical_cast(n+1) + " guanacos."; - -//----------------------------- -std::cout << "I have " + boost::lexical_cast(n+1) + " guanacos." << std::endl; - - -// @@PLEAC@@_1.11 -//----------------------------- -// C++ does not have "here documents". -// TODO: Lots more. -#include -#include "boost/regex.hpp" - -std::string var = " - your text - goes here. -"; - -boost::regex ex("^\\s+"); -var = boost::regex_merge(var, ex, ""); - -// @@PLEAC@@_10.0 -// 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 - -// '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; -} - -// @@PLEAC@@_10.1 -// 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 - -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 -#include - -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 - -// 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 - -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 -#include - -std::vector int_all(const double arr[], size_t arrsize); -std::vector int_all(const std::vector& 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 ints = int_all(nums, arrsize); - - // Vector -> vector copy / conversion - ints = int_all(std::vector(nums, nums + arrsize)); -} - -// ---- - -std::vector int_all(const double arr[], size_t arrsize) -{ - return std::vector(arr, arr + arrsize); -} - -std::vector int_all(const std::vector& arr) -{ - std::vector r; - r.assign(arr.begin(), arr.end()); // Type safe element copying - return r; -} - -// ---------------------------- - -#include -#include - -#include -#include - -void trunc_em(std::vector& 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 numsv(nums, nums + arrsize); - - trunc_em(numsv); -} - -// ---- - -void trunc_em(std::vector& arr) -{ - // Replace each element with the value returned by applying 'floor' to that element - std::transform(arr.begin(), arr.end(), arr.begin(), floor); -} - -// @@PLEAC@@_10.2 -// 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 - -void somefunc() -{ - // All these variables are local to this function - int variable, another; - - std::vector 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 -#include - -class bad_conversion {}; - -template T fromString(const std::string& s) -{ - std::istringstream iss(s); - T t; iss >> t; - if (!iss) throw bad_conversion(); - return t; -} - -template std::string toString(const T& t) -{ - std::ostringstream oss; - oss << t << std::ends; - if (!oss) throw bad_conversion(); - return std::string(oss.str()); -} - -// ------------ - -#include - -// 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(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) - { - ; // ... - } -} - -// @@PLEAC@@_10.3 -// 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 -#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 -#include "counter.h" - -int main() -{ - int a = Counter::increment(); - std::cout << a << std::endl; - - a = Counter::decrement(); - std::cout << a << std::endl; -} - -// @@PLEAC@@_10.4 -// 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 - -// @@PLEAC@@_10.5 -// 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 -#include - -// 'pass-by-value': a copy of each vector is passed as an argument -// void array_diff(const std::vector arr1, const std::vector 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& arr1, const std::vector& arr2); -// * Disallow vector replacement only -// void array_diff(const std::vector& arr1, const std::vector& arr2); -// * Disallow alteration of vector contents only -// void array_diff(std::vector& arr1, std::vector& arr2); -// * Allow replacement / alteration -// void array_diff(std::vector& arr1, std::vector& arr2); - -void array_diff(const std::vector& arr1, const std::vector& 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(arr1, arr1 + arrsize), std::vector(arr2, arr2 + arrsize)); -} - -// ---- - -// void array_diff(const std::vector arr1, const std::vector arr2) -// { -// ; // 'arr1' and 'arr2' are copies of the originals -// } - -void array_diff(const std::vector& arr1, const std::vector& arr2) -{ - ; // 'arr1' and 'arr2' are references to the originals -} - -// ---------------------------- - -#include - -#include -#include -#include - -std::vector add_vecpair(const std::vector& arr1, const std::vector& 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 a(aa, aa + arrsize), b(ba, ba + arrsize); - - std::vector c = add_vecpair(a, b); -} - -// ---- - -std::vector add_vecpair(const std::vector& arr1, const std::vector& arr2) -{ - std::vector retvec; retvec.reserve(arr1.size()); - std::transform(arr1.begin(), arr1.end(), arr2.begin(), back_inserter(retvec), std::plus()); - return retvec; -} - -// @@PLEAC@@_10.6 -// 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 - -#include -#include - -template 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 v = mysub(std::vector(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("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 -#include - -#include - -template boost::any mysub(const T& t) { return boost::any(t); } - -// ---- - -int main() -{ - std::vector 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(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(any[0]); - double d = boost::any_cast(any[1]); - std::vector v = boost::any_cast< std::vector >(any[2]); - std::string s = boost::any_cast(any[3]); -} - -// @@PLEAC@@_10.7 -// 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 -#include - -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 TENTRY; -typedef std::map 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(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. - -// @@PLEAC@@_10.8 -// The Boost 'tuple' Library also allows multiple assignment to variables, including the -// selective skipping of return values - -#include - -#include - -typedef boost::tuple 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); } - -// @@PLEAC@@_10.9 -// 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 -#include -#include - -#include -#include - -#include -#include - -typedef std::vector ARRAY; -typedef std::map HASH; -typedef boost::tuple 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); -} - -// @@PLEAC@@_10.10 -// 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 - -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 - -#include - -#include -#include -#include - -#include - -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 sfunc(); -boost::optional< std::vector > afunc(); -boost::optional< std::map > hfunc(); - -// ------------ - -int main() -{ - try - { - boost::optional s; - boost::optional< std::vector > a; - boost::optional< std::map > 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 sfunc() -{ - bool error_detected = true; - - int valid_int_value; - - ; // ... - - if (error_detected) return boost::optional(); - - ; // ... - - return boost::optional(valid_int_value); -} - -boost::optional< std::vector > afunc() -{ - // ... code not shown ... - - return boost::optional< std::vector >(); - - // ... code not shown -} - -boost::optional< std::map > hfunc() -{ - // ... code not shown ... - - return boost::optional< std::map >(); - - // ... code not shown ... -} - -// @@PLEAC@@_10.11 -// 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 -#include - -// Function Declaration -std::vector myfunc(int arg1, int arg2); // Also possible: std::vector 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 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 myfunc(int arg1, int arg2) -{ - std::vector 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 -#include - -// Function Declaration -template std::vector myfunc(const T& arg1, const T& arg2); - -// ---- - -int main() -{ - std::vector results = myfunc(3, 5); - - std::cout << results[0] << ':' << results[1] << std::endl; -} - -// ---- - -// Function Definition -template std::vector myfunc(const T& arg1, const T& arg2) -{ - std::vector 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 - -// @@PLEAC@@_10.12 -// 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 -#include - -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; -} - -// @@PLEAC@@_10.13 -// 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(); -} - -// @@PLEAC@@_10.14 -// 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@@ - -// @@PLEAC@@_10.15 -// 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@@ - -// @@PLEAC@@_10.16 -// 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 - -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(); -} - -// @@PLEAC@@_10.17 -// @@INCOMPLETE@@ -// @@INCOMPLETE@@ - -- cgit v1.2.1