读书笔记之:C++探秘——68讲贯通C++

第1讲 打磨工具

1. C++/CLI与C++是不同的

第2讲 阅读C++代码

1.核心语言与标准库

C++与C以及其他很多语言类似,区分核心语言与标准库。核心语言和标准库都是标准语言的一部分,不包含这二者的工具套件是不完整的。

二者的区别在于核心语言是自包含的。例如,有些类型是语言内建的,编译器对其提供内在的支持,而其他类型是通过内建类型来定义的,他们在标准库中声明,使用时需要通知编译器将其导入。

第3讲 整数表达式

第17讲 字符集

1. 单词计数:将单词限定为字母和类字母的字符

代码如下:

View Code
#include <iostream>
#include <iomanip>
#include <map>
#include < string>
using  namespace std;
int main(){
    map< string, int> counts;
     string word;

     string okay( " ABCDEFGHIJKLMNOPQRSTUVWXYZ "
             " abcdefghijklmnopqrstuvwxyz "
             " 0123456789_ ");
     while(cin>>word){
         string copy;
         for( string::iterator w(word.begin());w!=word.end();++w)
             if(okay.find(*w)!= string::npos)
                copy.push_back(*w);
             else
            {
                 if(!copy.empty())
                    ++counts[copy];
                copy.clear();
            }
//         if(!copy.empty())
//             ++counts[copy];
    }
    size_t longest( 0);
   typename map< string, int>::iterator ite;
    for(ite=counts.begin();ite!=counts.end();++ite)
        if(ite->first.size()>longest)
           longest=ite->first.size();
    const  int count_size( 10);
    for(ite=counts.begin();ite!=counts.end();++ite)
       cout<<setw(longest)<<left<<ite->first<<
           setw(count_size)<<right<<ite->second<< ' \n ';
}

 

第26讲 项目1:身体质量指数

代码如下:

View Code
/* * @file
 * @brief Compute body-mass index.
 
*/
/* * @mainpage Project 1 - Body-Mass Index
 * This program is Project 1 in <em>Exploring C++</em>,
 * by Ray Lischner (Apress).
 *
 * Your task is to write a program that reads records,
 * prints the records, and computes some statistics.
 * The program starts by asking for a threshold BMI.
 * Only records with a BMI greater than or equal to the
 * threshold will be printed. Each record consists of a
 * person's name (which might contain spaces), weight in
 * kilograms, height in centimeters (not meters), and
 * the person's sex ('M' or 'F'). Let the user enter
 * the sex in uppercase or lowercase.
 *
 * Print each person's BMI after reading that person's record.
 * After collecting information for everyone, print two tables
 * of the information. One table is for men and the other is
 * for women. Mark records for which the BMI meets or exceeds
 * the threshold with an asterisk after the BMI. After each table,
 * print the mean (average) and median BMI. (Median is the value
 * such that half the BMI values are less than the median and half
 * are greater than the median. If the user enters an even number
 * of records, take the average of the two values in the middle.)
 * Compute individual BMI values as integers. Compute the mean and
 * median BMIs as floating point numbers, and print the mean with
 * one place after the decimal point.
 *
 * Body-mass index is defined as weight in kg/(height in m)<sup>2</sup>,
 * converted to a unitless number.
 *
 * Source file:
 * @link bmi.cpp bmi.cpp @endlink
 * @author Ray Lischner
 
*/

#include <algorithm>
#include <cstdlib>
#include <iomanip>
#include <iostream>
#include <istream>
#include <limits>
#include <locale>
#include <ostream>
#include < string>
#include <vector>

/* * @brief Compute the body-mass index (BMI).
 * The height is in centimeters, so the computed value
 * is off by 10,000. Integer division truncates, but we
 * want to round off to nearest, so add 0.5 and then
 * truncate by casting to an integer.
 *
 * @param height The person's height in centimeters.
 * @param weight The person's weight in kilograms.
 * @return the person's BMI, rounded to an integer
 
*/
int compute_bmi( int height,  int weight)
{
    return static_cast< int>(weight *  10000 / (height * height) +  0.5);
}

/* * @brief Skip the rest of the input line.  */
void skip_line()
{
  std::cin.ignore(std::numeric_limits< int>::max(),  ' \n ');
}

/* * @brief Get a single person's record.
 * Store the name, height, weight, and sex in the supplied vectors.
 * @param names array of persons' full names
 * @param heights array of height in centimeters
 * @param weights array of weight in kilograms
 * @param sexes array of persons' sex: 'M' means male and 'F' means female
 * @return true to continue reading records or false to stop
 
*/
bool get_record(std::vector<std:: string>& names,
                std::vector< int>& heights,
                std::vector< int>& weights,
                std::vector< char>& sexes)
{
   std:: string name;
    int height( 0);
    int weight( 0);
    char sex( ' ? ');

  std::cout <<  " Name  " << names.size()+ 1 <<  " ";
   if (not std::getline(std::cin, name))
     return  false;

   //  Enforce minimal sanity check on the height, which must be
  
//  between 10 and 300 cm, or baby- to giant-size.
   int  const min_height( 10);
   int  const max_height( 300);
  std::cout <<  " Height (cm):  ";
   if (not (std::cin >> height))
     return  false;
  skip_line();
   if (height < min_height or height > max_height)
  {
    std::cout <<  " Invalid height. Aborting.\n ";
     return  false;
  }

   //  Enforce minimal sanity check on the weight, which must
  
//  be between premature-baby and giant size.
   const  int min_weight( 1);
   const  int max_weight( 500);
  std::cout <<  " Weight (kg):  ";
   if (not (std::cin >> weight))
     return  false;
  skip_line();
   if (weight < min_weight or weight > max_weight)
  {
    std::cout <<  " Invalid weight. Aborting.\n ";
     return  false;
  }

  std::cout <<  " Sex (M or F):  ";
   if (not (std::cin >> sex))
     return  false;
  skip_line();
  sex = std::toupper(sex, std::locale());
   if (sex !=  ' M ' and sex !=  ' F ')
  {
    std::cout <<  " Invalid sex. Aborting.\n ";
     return  false;
  }

   //  All information has now been collected, so
  
//  append it all to the respective vectors.
  names.push_back(name);
  heights.push_back(height);
  weights.push_back(weight);
  sexes.push_back(sex);

   return  true;
}

/* * @brief Print a table.
 * Print a table of height, weight, sex, BMI, and name.
 * Print only records for which sex matches @p sex.
 * At the end of each table, print the mean and median BMI.
 *
 * @param sex the sex to match
 * @param heights the array of heights
 * @param weights the array of weights
 * @param bmis the array of BMIs
 * @param sexes the array of sexes
 * @param names the array of names
 * @param threshold print only elements for which BMI > this
 
*/
void print_table( char sex,
                 std::vector< int>          const& heights,
                 std::vector< int>          const& weights,
                 std::vector< int>          const& bmis,
                 std::vector< char>         const& sexes,
                 std::vector<std:: stringconst& names,
                  int                      threshold)
{
  std::cout <<  " Ht(cm) Wt(kg) Sex  BMI  Name\n ";

   float bmi_sum( 0);
   long  int bmi_count( 0);
  std::vector< int> tmpbmis;  //  store only the BMIs that are printed
                            
//  to compute the median
   for (std::vector< int>::size_type i( 0); i != heights.size(); ++i)
     if (sexes.at(i) == sex)
    {
      bmi_sum = bmi_sum + bmis.at(i);
      ++bmi_count;
      tmpbmis.push_back(bmis.at(i));
      std::cout << std::setw( 6) << heights.at(i)
                << std::setw( 7) << weights.at(i)
                << std::setw( 3) << sexes.at(i)
                << std::setw( 6) << bmis.at(i);
       if (bmis.at(i) >= threshold)
        std::cout <<  ' * ';
       else
        std::cout <<  '   ';
      std::cout <<  '   ' << names.at(i) <<  ' \n ';
    }

   //  If the vectors are not empty, print basic statistics.
   if (bmi_count !=  0)
  {
    std::cout <<  " Mean BMI =  "
              << std::setprecision( 1) << std:: fixed << bmi_sum / bmi_count
              <<  ' \n ';

     //  Median BMI is trickier. The easy way is to sort the
    
//  array and pick out the middle item or items.
    std::sort(tmpbmis.begin(), tmpbmis.end());
    std::cout <<  " Median BMI =  ";
     //  Index of median item.
     int i(tmpbmis.size() /  2);
     if (tmpbmis.size() %  2 ==  0)
      std::cout << (tmpbmis.at(i) + tmpbmis.at(i- 1)) /  2.0 <<  ' \n ';
     else
      std::cout << tmpbmis.at(i) <<  ' \n ';
  }
}

/* * @brief Main program to compute BMI.  */
int main()
{
  std::locale:: global(std::locale( ""));
  std::cout.imbue(std::locale());
  std::cin.imbue(std::locale());

  std::vector<std:: string> names;
  std::vector< int>         heights;
  std::vector< int>         weights;
  std::vector< char>        sexes;
  std::vector< int>         bmis;
   int threshold;

  std::cout <<  " Enter threshold BMI:  ";
   if (not (std::cin >> threshold))
     return EXIT_FAILURE;
  skip_line();

  std::cout <<  " Enter name, height (in cm), "
                "  and weight (in kg) for each person:\n ";
   while (get_record(names, heights, weights, sexes))
  {
     int bmi(compute_bmi(heights.back(), weights.back()));
    bmis.push_back(bmi);
    std::cout <<  " BMI =  " << bmi <<  ' \n ';
  }

   //  Print the data.
  std::cout <<  " \n\nMale data\n ";
  print_table( ' M ', heights, weights, bmis, sexes, names, threshold);
  std::cout <<  " \nFemale data\n ";
  print_table( ' F ', heights, weights, bmis, sexes, names, threshold);
}

 

第33讲 访问级别

1. 简单旧式数据

第37讲 类与类型

1. RAAI资源获取即为初始化

第43讲 异常

1. 程序栈/执行栈/调用栈/堆栈帧

原书给出的代码:

View Code
#include <exception>
#include <iostream>
#include <istream>
#include <ostream>
#include < string>

///  Make visual the construction and destruction of objects.
class visual
{
public:
  visual(std:: string  const& what)
  : id_(serial_), what_(what)
  {
    ++serial_;
    print( "");
  }
  visual(visual  const& ex)
  : id_(ex.id_), what_(ex.what_)
  {
    print( " copy  ");
  }
  ~visual()
  {
    print( " ~ ");
  }
   void print(std:: string  const& label)
   const
  {
    std::cout << label <<  " visual( " << what_ <<  " " << id_ <<  " )\n ";
  }
private:
   static  int serial_;
   int  const id_;
  std:: string  const what_;
};

int visual::serial_( 0);

void count_down( int n)
{
  std::cout <<  " start count_down( " << n <<  " )\n ";
  visual v( " count_down local ");
   try
  {
     if (n ==  3)
       throw visual( " exception ");
     else  if (n >  0)
      count_down(n -  1);
  }
   catch (visual ex)
  {
    ex.print( " catch  ");
     throw;
  }
  std::cout <<  " end count_down( " << n <<  " )\n ";
}

int main()
{
   try
  {
    count_down( 2);
    count_down( 4);
  }
   catch (visual  const ex)
  {
    ex.print( " catch  ");
  }
  std::cout <<  " All done!\n ";
}

 为了便于查看,对代码做了简单的修改,结果如上图所示:

View Code
 1 #include <exception>
 2 #include <iostream>
 3 #include <istream>
 4 #include <ostream>
 5 #include < string>
 6 
 7  ///  Make visual the construction and destruction of objects.
 8  class visual
 9 {
10  public:
11   visual(std:: string  const& what)
12   : id_(serial_), what_(what),preid(- 1)
13   {
14     ++serial_;
15     print( "");
16   }
17   visual(visual  const& ex)
18   : id_(serial_), what_(ex.what_),preid(ex.id_)
19   {
20     ++serial_;print( " copy  ");
21   }
22   ~visual()
23   {
24     print( " ~ ");
25   }
26    void print(std:: string  const& label)
27    const
28   {
29     std::cout << label <<  " visual( " << what_ <<  " : id= " << id_ <<  " ,preid=  "<<preid<< " )\n ";
30   }
31  private:
32    static  int serial_;
33    int  const id_; int preid;
34   std:: string  const what_;
35 };
36 
37  int visual::serial_( 0);
38 
39  void count_down( int n)
40 {
41   std::cout <<  " start count_down( " << n <<  " )\n ";
42   visual v( " count_down local ");
43    try
44   {
45      if (n ==  3)
46        throw visual( " exception ");
47      else  if (n >  0)
48       count_down(n -  1);
49   }
50    catch (visual ex)
51   {
52     ex.print( " catch-A  ");
53      throw;
54   }
55   std::cout <<  " end count_down( " << n <<  " )\n ";
56 }
57 
58  int main()
59 {
60    try
61   {
62     count_down( 2);
63     count_down( 4);
64   }
65    catch (visual  const ex)
66   {
67     ex.print( " catch-B  ");
68   }
69   std::cout <<  " All done!\n ";
70 }

 第45讲 项目2:定点数

代码如下:

(1)类定义:

View Code
/* * @file
 * @brief Fixed-point numbers.
 
*/
/* * @mainpage Project 2 - FIxed-Point Numbers
 * This program is Project 2 in <em>Exploring C++</em>,
 * by Ray Lischner (Apress).
 *
 * Your task for Project 2 is to implement a simple fixed-point
 * number class. The class represents fixed-point numbers using
 * an integer type. The number of places after the decimal point
 * is a fixed constant, four. For example, represent the number
 * 3.1415 as the integer 31415 and 3.14 as 31400. You must overload
 * the arithmetic, comparison, and I/O operators to maintain the
 * fixed-point fiction.
 *
 * Source files:
 *  - @link fixed.hpp fixed.hpp @endlink
 *  - @link fixed.cpp fixed.cpp @endlink
 *  - @link test.cpp test.cpp @endlink: test program
 *  - @link test.hpp test.hpp @endlink: test header (see Exploration 28)
 *  - @link ioflags.hpp ioflags.hpp @endlink: save and restore I/O stream flags (Exploration 37)
 *
 * @author Ray Lischner
 
*/

#ifndef FIXED_HPP_
#define FIXED_HPP_

#include <istream>
#include <ostream>
#include < string>

/* * @brief Implement a fixed-point number class.
 * Values have @c places places after the decimal point.
 * All arithmetic follows the usual rules.
 
*/
class  fixed
{
public:
  typedef  int value_type;                     /// < Type of the actual value

   static  int  const places =  4;                /// < number of decimal places
  static value_type const places10 = 10000;   /// < 10<sup> places </sup>

  
///  Default constructor initializes to zero.
   fixed() : value_( 0) {}

   ///  Construct from separate integer and fractional parts,
  
///  e.g., initialize to 123.45 with fixed(123, 45). Initialize
  
///  to 12.07 with fixed(12, 7).
   fixed(value_type integer, value_type fraction);

   ///  Construct from an integer, with no fraction.
   fixed(value_type integer);

   ///  Construct by rounding off a floating point number.
   fixed( double value)
  : value_(static_cast<value_type>(value * places10 + (value <  0 ? - 0.5 :  0.5)))
  {}

   ///  Convert to a string.
  
///  @returns a string representation of the value, e.g., "123.04"
  std:: string as_string()  const;
   ///  Read from a stream.
  
///  Overwrite this value with the value read from the stream.
  
///  @param strm the stream to read
  
///  @returns true for success or false for failure
   bool read(std::istream& strm);
   ///  Convert to long double.
   double as_long_double()  const {  return static_cast< long  double>(value()) / places10; }
   ///  Convert to double.
   double as_double()  const {  return static_cast< double>(value()) / places10; }
   ///  Convert to float
   float as_float()  const {  return static_cast< float>(value()) / places10; }
   ///  Return just the integer part, rounded off to the nearest integer.
  
///  If the value lies equidistant between two integers, round even
  
///  numbers up and odd numbers down (banker's rounding).
  value_type round()  const;

   ///  Return the integer part (which is the same as trunc()).
  value_type integer()  const {  return value() / places10; }
   ///  Return the fractional part, e.g., 3 for 12.03
  value_type fraction()  const;

   ///  Addition assignment operator
   fixedoperator+=( fixed f);
   ///  Subtraction assignment operator
   fixedoperator-=( fixed f);
   ///  Multiplication assignment operator
   fixedoperator*=( fixed f);
   ///  Division assignment operator
   fixedoperator/=( fixed f);

   ///  Negate this value.
   void negate();

   ///  Pre-increment
   fixedoperator++();
   ///  Post-increment
   fixed  operator++( int);
   ///  Pre-decrement
   fixedoperator--();
   ///  Post-decrement
   fixed  operator--( int);

   ///  Return the internal value.
  value_type value()     const {  return value_; }
private:
   ///  Reduce frac to the range [0, places10) by discarding digits to the right.
  value_type reduce(value_type frac);
  value_type value_;
};

///  Read a fixed value
std::istream&  operator>>(std::istream& strm,  fixed& f);
///  Write a fixed value
std::ostream&  operator<<(std::ostream& strm,  fixed f);

///  Add fixed values
fixed  operator+( fixed a,  fixed b);
///  Subtract fixed values
fixed  operator-( fixed a,  fixed b);
///  Multiply fixed values
fixed  operator*( fixed a,  fixed b);
///  Divide fixed values
fixed  operator/( fixed a,  fixed b);
///  Negate a fixed value
fixed  operator-( fixed a);

///  Compare fixed values for equality by comparing the underlying values.
bool  operator==( fixed a,  fixed b);
///  Compare fixed values for inequality by comparing the underlying values.
bool  operator!=( fixed a,  fixed b);
///  Compare fixed values for less-than by comparing the underlying values.
bool  operator<( fixed a,  fixed b);
///  Compare fixed values for greater-than by comparing the underlying values.
bool  operator>( fixed a,  fixed b);
///  Compare fixed values for less-than-or-equal by comparing the underlying values.
bool  operator<=( fixed a,  fixed b);
///  Compare fixed values for greater-than-or-equal by comparing the underlying values.
bool  operator>=( fixed a,  fixed b);

#endif

 

(2)类实现:

View Code
#include <cassert>
#include <cstdlib>
#include <iomanip>
#include <istream>
#include <locale>
#include <ostream>
#include <sstream>
#include <sstream>
#include <stdexcept>
#include < string>

#include  " fixed.hpp "
#include  " ioflags.hpp "

//  Construct a fixed value from an integer part and a fraction part
fixed:: fixed(value_type integer, value_type fraction)
{
   if (fraction <  0)
     throw std::invalid_argument( " negative fraction not allowed ");
  fraction = reduce(fraction);
   if (integer <  0)
    value_ = integer * places10 - fraction;
   else
    value_ = integer * places10 + fraction;
}

//  Construct a fixed value from an integer part with no fraction
fixed:: fixed(value_type integer)
: value_(integer * places10)
{}

//  Get the fraction part
fixed::value_type  fixed::fraction()
const
{
   return std::abs(value()) % places10;
}

///  Reduce the fractional part to the range [0, places10).
///  Imagine frac has the format F(G(XY*)?)?.
///  The resulting value is FH, where H == 0 if G is absent,
///  or H == G+1 if X==5 and Y* == 0* and G is odd, or
///  H == G+1 if X>5 or X==5 and Y*>0*, else H == G.
///  In other words, check that frac ends with only zero digits,
///  then a 5, then two more digits (searching from least-significant
///  to most-significant). If so, implement banker's rounding.
///  Otherwise, round GXY* to the nearest value (G+1 or G).
fixed::value_type  fixed::reduce(value_type frac)
{
   //  First scan for zero digits on the right.
  value_type f(frac);
   while (f >= places10* 10 and f %  10 ==  0)
  {
    f /=  10;
  }

   if (f >= places10* 10)
  {
     int x( 0);
     //  Loop ended because a non-zero digit was seen so Y* > 0.
    
//  Discard the remaining digits, but keep track of the last
    
//  digit to be processed (X).
     while (f >= places10)
    {
      x = f %  10;
      f /=  10;
    }
     //  Round up if the last digit (X) is 5 or more
     if (x >=  5)
      ++f;
     return f;
  }
   //  Else all digits so far are zero. Check how many digits there were,
  
//  that is, check whether G, and X at least are present.
   else  if (f >= places10)
  {
     //  Yes, G and X are present. If X == 5, implement banker's rounding.
    
//  Otherwise, round to nearest.
     int x(f %  10);
    f /=  10;
    assert(f < places10);
     if (x ==  5)
    {
       //  Yes, so implement banker's rounding.
       if (f %  2 !=  0)
        ++f;
       return f;
    }
     else  if (x <  5)
    {
       //  Round down.
       return f;
    }
     else
    {
       //  Round up.
       return f +  1;
    }
  }
   //  Not enough digits, so nothing to round.
  assert(frac < places10);
   return frac;
}

//  Round off to nearest integer.
fixed::value_type  fixed::round()
const
{
   const value_type frac(fraction());
   int adjust(value() <  0 ? - 1 : + 1);
   if (frac > places10/ 2)
     return integer()+adjust;
   else  if (frac < places10/ 2)
     return integer();
   else  if (integer() %  2 ==  0)
     return integer();
   else
     return integer()+adjust;
}

//  Convert to a string using fixed-point notation.
std:: string  fixed::as_string()
const
{
  std::ostringstream  out;
   out << integer() <<  ' . '
      << std::setfill( ' 0 ') << std::setw(places) << fraction();
   return  out.str();
}

fixedfixed:: operator+=( fixed f)
{
  value_ += f.value();
   return * this;
}

fixedfixed:: operator-=( fixed f)
{
  value_ -= f.value();
   return * this;
}

fixedfixed:: operator*=( fixed f)
{
  value_ = (value_ * f.value()) / places10;
   return * this;
}

fixedfixed:: operator/=( fixed f)
{
  value_ = (value_ * places10) / f.value();
   return * this;
}

void  fixed::negate()
{
  value_ = -value_;
}

fixedfixed:: operator++()
{
  value_ += places10;
   return * this;
}

fixed  fixed:: operator++( int)
{
   fixed result(* this);
  ++* this;
   return result;
}

fixedfixed:: operator--()
{
  value_ -= places10;
   return * this;
}

fixed  fixed:: operator--( int)
{
   fixed result(* this);
  --* this;
   return result;
}

fixed  operator-( fixed a)
{
  a.negate();
   return a;
}

bool  fixed::read(std::istream& strm)
{
  ioflags flags(strm);

  value_type integer;
   char  decimal;
   if (not (strm >> integer))
     return  false;
  strm.unsetf(std::ios_base::skipws);
   if (not (strm >>  decimal) or  decimal !=  ' . ')
  {
     //  Just an integer is fine. Push back the non-decimal character,
    
//  if there is one, and reset the stream flags to show that
    
//  reading the fixed value succeeded.
    strm.unget();
    strm.clear(strm.rdstate() & ~strm.failbit);
    value_ = integer * places10;
     return  true;
  }
   else
  {
    value_type fraction( 0);
     char c;
     int p( 0);
     //  Read one extra place for round-off.
     for (;
         p != places+ 1 and strm >> c and std::isdigit(c, strm.getloc());
         ++p)
    {
        fraction = fraction *  10 + (c -  ' 0 ');
    }
     //  Pad out to the requisite number of decimal places.
     for (; p < places; ++p)
      fraction = fraction *  10;
     //  If the loop terminated because the maximum number of decimal
    
//  places were read, keep reading the stream to discard excees digits.
     while (strm and std::isdigit(c, strm.getloc()))
      strm >> c;
     //  Push back the last, non-digit character read from the stream.
    
//  If the stream reached EOF, unget() is harmless.
    strm.unget();
     //  Clear failbit because even if reading a character or whatever
    
//  failed, reading the fixed value did not.
    strm.clear(strm.rdstate() & ~strm.failbit);
    fraction = reduce(fraction);
     if (integer <  0)
      value_ = integer * places10 - fraction;
     else
      value_ = integer * places10 + fraction;
  }
   return  true;
}

std::istream&  operator>>(std::istream& strm,  fixed& f)
{
   if (not f.read(strm))
    strm.setstate(strm.failbit);
   return strm;
}

std::ostream&  operator<<(std::ostream& strm,  fixed f)
{
  strm << f.as_string();
   return strm;
}

fixed  operator+( fixed a,  fixed b)
{
  a += b;
   return a;
}

fixed  operator-( fixed a,  fixed b)
{
  a -= b;
   return a;
}

fixed  operator*( fixed a,  fixed b)
{
  a *= b;
   return a;
}

fixed  operator/( fixed a,  fixed b)
{
  a /= b;
   return a;
}

bool  operator==( fixed a,  fixed b)
{
   return a.value() == b.value();
}

bool  operator!=( fixed a,  fixed b)
{
   return not (a == b);
}

bool  operator<( fixed a,  fixed b)
{
   return a.value() < b.value();
}

bool  operator>( fixed a,  fixed b)
{
   return b < a;
}

bool  operator<=( fixed a,  fixed b)
{
   return not (b < a);
}

bool  operator>=( fixed a,  fixed b)
{
   return not (a < b);
}

 

(3)异常定义:

View Code
#ifndef TEST_HPP_
#define TEST_HPP_

#include <exception>
#include <iostream>
#include <ostream>

//  For internal use by the test() macro.
//  Turn the macro argument into a character string literal
#define test_stringify(x) #x

//  For internal use by the test() macro.
//  Report a test failure.
inline  void test_failed( char  const* expr,  char  const* file,  int line)
{
   std::cerr << file <<  " , line  " << line <<  " : test failed:  " << expr <<  ' \n ';
}

//  For internal use by the test() macro
//  Run a test. Report a failure if the condition is false or
inline  void test_run( bool condition,  char  const* expr,  char  const* file,  int line)
{
   if (not condition)
    test_failed(expr, file, line);
}

//  For internal use by the test() macro.
//  Report an exception.
inline  void test_exception(std::exception  const& ex,  char  const* expr,  char  const* file,  int line)
{
  std:: string msg( expr );
  msg +=  "  threw an exception:  ";
  msg += ex.what();
  test_failed(msg.c_str(), file, line);
}

///  Test a condition, @p x.
///  If @p x evaluates to @c true the test passes.
///  If not, the test fails, and a message is printed to @c cerr.
///  The text of @p x, plus the file name and line number are printed.
///
///  See Boost.Test for a real test framework
///
///  @param x A condition to test; the condition must be able to be converted implicitly to @c bool.
#define test(x) \
try {\
  test_run(x, test_stringify(x), __FILE__, __LINE__);\
}\
catch(std::exception  const& ex)\
{\
  test_exception(ex, test_stringify(x), __FILE__, __LINE__);\
}

#endif

(4)测试代码:

View Code
/* * @file test.cpp  */
/* * Listing 45-1. Testing the fixed Class  */
#include <iostream>
#include <istream>
#include <ostream>
#include <sstream>
#include <stdexcept>

#include  " test.hpp "
#include  " fixed.hpp "

int main()
{
   fixed f1;
  test(f1.value() ==  0);
   fixed f2( 1);
  test(f2.value() ==  10000);
   fixed f3( 314162);
  test(f3.value() ==  31416);
   fixed f4( 214159265);
  test(f4.value() ==  21416);
  test(f2 + f4 == f1 + f3);
  test(f2 + f4 <= f1 + f3);
  test(f2 + f4 >= f1 + f3);
  test(f1 < f2);
  test(f1 <= f2);
  test(f1 != f2);
  test(f2 > f1);
  test(f2 >= f1);
  test(f2 != f1);

  test(f2 + f4 == f3 - f1);
  test(f2 * f3 == f3);
  test(f3 / f2 == f3);
  f4 += f2;
  test(f3 == f4);
  f4 -= f1;
  test(f3 == f4);
  f4 *= f2;
  test(f3 == f4);
  f4 /= f2;
  test(f3 == f4);

  test(-f4 == f1 - f4);
  test(-(-f4) == f4);
  --f4;
  test(f4 +  1 == f3);
  f4--;
  test(f4 +  2 == f3);
  ++f4;
  test(f4 +  1 == f3);
  f4++;
  test(f4 == f3);
  ++f3;
  test(++f4 == f3);
  test(f4-- == f3);
  test(f4++ == --f3);
  test(--f4 == f3);

  test(f4 / f3 == f2);
  test(f4 - f3 == f1);

  test(f4.as_string() ==  " 3.1416 ");
  test(f4.integer() ==  3);
  f4 +=  fixed( 0, 4584);
  test(f4 ==  3.6);
  test(f4.integer() ==  3);
  test(f4.round() ==  4);

  test(f3.integer() ==  3);
  test((-f3).integer() == - 3);
  test(f3.fraction() ==  1416);
  test((-f3).fraction() ==  1416);

  test( fixed( 7, 4999).round() ==  7);
  test( fixed( 7, 5000).round() ==  8);
  test( fixed( 7, 5001).round() ==  8);
  test( fixed( 7, 4999).round() ==  7);
  test( fixed( 8, 5000).round() ==  8);
  test( fixed( 8, 5001).round() ==  9);

  test( fixed( 123, 2345500) ==  fixed( 123, 2346));
  test( fixed( 123, 2345501) ==  fixed( 123, 2346));
  test( fixed( 123, 2345499) ==  fixed( 123, 2345));
  test( fixed( 123, 2346500) ==  fixed( 123, 2346));
  test( fixed( 123, 2346501) ==  fixed( 123, 2347));
  test( fixed( 123, 2346499) ==  fixed( 123, 2346));
  test( fixed( 123, 2346400) ==  fixed( 123, 2346));
  test( fixed( 123, 2346600) ==  fixed( 123, 2347));

  test( fixed(- 7, 4999).round() == - 7);
  test( fixed(- 7, 5000).round() == - 8);
  test( fixed(- 7, 5001).round() == - 8);
  test( fixed(- 7, 4999).round() == - 7);
  test( fixed(- 8, 5000).round() == - 8);
  test( fixed(- 8, 5001).round() == - 9);

  test( fixed(- 3.14159265).value() == - 31416);
  test( fixed( 123, 456789).value() ==  1234568);
  test( fixed( 123, 4).value() ==  1230004);
  test( fixed(- 10, 1111).value() == - 101111);

  std::ostringstream  out;
   out << f3 <<  "  3.14159265  " <<  fixed(- 10, 12) <<  "  3 421.4 end ";
   fixed f5;
  std::istringstream  in( out.str());
  test( in >> f5);
  test(f5 == f3);
  test( in >> f5);
  test(f5 == f3);
  test( in >> f5);
  test(f5.value() == - 100012);
  test( in >> f5);
  test(f5.value() ==  30000);
  test( in >> f5);
  test(f5.value() ==  4214000);
  test(not ( in >> f5));

  test( fixed( 31.4159265) ==  fixed( 314159));
  test( fixed( 31.41595) ==  fixed( 314160));

   bool okay( false);
   try {
     fixed f6( 1, - 1);
  }  catch (std::invalid_argument  const& ex) {
    okay =  true;
  }  catch (...) {
  }
  test(okay);
}

第51讲 容器

1. 各种容器的复杂度

2. C++技术报告TR1

第54讲 文件I/O

1. 整数/浮点等转化为字符串

#include <ostream>  //  for the << operator
#include <sstream>  //  for ostringstream
#include < string>   //  for string

template< class T>
std:: string to_string(T  const& obj)
{
  std::ostringstream  out;
   out << obj;
   return  out.str();
}

2. 从字符串得到整数/浮点数

#include <istream>  //  for the >> operator
#include <sstream>  //  for ostringstream
#include < string>   //  for string
#include  " conversion_error.hpp "

template< class T>
T from_string(std:: string  const& str)
{
  std::istringstream  in(str);
  T result;
   if ( in >> result)
     return result;
   else
     throw conversion_error(str);
}

 

第55讲 项目3:货币类型

currency.hpp:

View Code
/* * @file currency.hpp
 * Implement a currency type.
 
*/

#ifndef CURRENCY_HPP_
#define CURRENCY_HPP_

#include <iomanip>
#include <istream>
#include <locale>
#include <ostream>
#include <sstream>
#include < string>
#include <stdexcept>

#include  " ioflags.hpp "
#include  " fixed.hpp "
#include  " rational.hpp "

/* * Class to represent a currency value in the global locale.  */
template< class T= longint N= 2>
class currency
{
public:
  typedef T int_type;                     /// < Storage type
  typedef fixed <T,N>  value_type;          /// < Type of the actual value

  
///  Default constructor initializes the value to zero.
  currency() : value_() {}
   ///  Initialize the value to @p integer
  
///  @param integer The integer initial value; the fractional part is zero.
  currency(T integer) : value_(integer) {}
   ///  Initialize the value.
  
///  The interpretation of the fractional part depends on @p N.
  
///  For example, if @p N is 2, a @p fraction of 9 represents 0.09,
  
///  buf if @p N is 5, @p fraction of 9 means 0.0009.
  
///  @param integer The integer part of the initial value
  
///  @param fraction The fractional part of the initial value
  currency(T integer, T fraction) : value_(integer, fraction) {}
   ///  Initialize from a floating point number.
  
///  @param value the initial value
  currency( double value) : value_(value) {}

   ///  Copy a value that uses a different precision.
  template< class U,  int M>
  currency(currency<U, M>  const& rhs): value_(rhs.value()) {}

   ///  Assign a value that uses a different precision.
  template< class U,  int M>
  currency&  operator=(currency<U, M> rhs)
  {
    value_ = rhs.value();
     return * this;
  }

   ///  Convert to a string.
  
///  @returns a string representation of the value, e.g., "$123.04"
  std:: string as_string()  const;
   ///  Overwrite this value with the value read from the stream.
  
///  The value in the stream must have the correct number of digits.
  
///  If the showbase flag is set, the currency symbol must be present.
  
///  @param strm Input stream
  
///  @return true if the read is success and @c *this has been modified,
  
///  or false if the read fails. Check @p strm for details.
  template< class Char,  class Traits>
   bool read(std::basic_istream<Char, Traits>& strm);

   ///  Convert the value to a different numeric type.
  
///  Typically, the other type is a floating-point type.
  template< class U>
   ///  Convert to some other type, especially floating point.
  U convert()  const {  return value().convert<U>(); }

   ///  Round off to the nearest integer, using banker's rounding.
  int_type round()  const {  return value().round(); }

   ///  Return the integer part (which is the same as trunc()).
  int_type integer()   const {  return value().integer(); }
   ///  Return the fractional part, to @p M places.
  template< int M>
  int_type fraction()  const {  return value().fraction<M>(); }
   ///  Return the fractional part.
  int_type fraction()  const {  return value().fraction(); }

   ///  Addition operator.
  
///  @param c the value to add
  
///  @return @c *this
  currency&  operator+=(currency c);
   ///  Subtraction operator.
  
///  @param c the value to subtract
  
///  @return @c *this
  currency&  operator-=(currency c);
   ///  Multiplication operator.
  
///  @param m the value to multiply
  
///  @return @c *this
  currency&  operator*=(value_type m);
   ///  Multiplication operator.
  
///  @param m the value to multiply
  
///  @return @c *this
  currency&  operator*=(int_type m);
   ///  Division operator.
  
///  @param m the divisor
  
///  @return @c *this
  currency&  operator/=(value_type m);
   ///  Division operator.
  
///  @param m the divisor
  
///  @return @c *this
  currency&  operator/=(int_type m);

   ///  Negate this value.
   void negate();

   ///  Pre-increment operator.
  currency&  operator++();
   ///  Post-increment operator.
  currency  operator++( int);
   ///  Pre-decrement operator.
  currency&  operator--();
   ///  Post-decrement operator.
  currency  operator--( int);

   ///  Return the internal value.
  value_type value()     const {  return value_; }

private:
  value_type value_;
};

template< class T,  int N>
std:: string currency<T,N>::as_string()
const
{
  std::ostringstream digits;
  digits.imbue(std::locale::classic());
  digits << integer() << std::setw(value_type::places) << std::setfill( ' 0 ') << fraction();

  std::ostringstream  out;
  std::money_put< charconst& put(std::use_facet<std::money_put< char> >(std::locale()));
  put.put(std::ostreambuf_iterator< char>( out),  falseout' 0 ', digits.str());
   return  out.str();
}

template< class T,  int N>
currency<T,N>& currency<T,N>:: operator+=(currency f)
{
  value_ += f.value();
   return * this;
}

template< class T,  int N>
currency<T,N>& currency<T,N>:: operator-=(currency f)
{
  value_ -= f.value();
   return * this;
}

template< class T,  int N>
currency<T,N>& currency<T,N>:: operator*=(value_type i)
{
  value_ *= i;
   return * this;
}
template< class T,  int N>
currency<T,N>& currency<T,N>:: operator*=(int_type i)
{
  value_ *= i;
   return * this;
}

template< class T,  int N>
currency<T,N>& currency<T,N>:: operator/=(value_type i)
{
  value_ /= i;
   return * this;
}
template< class T,  int N>
currency<T,N>& currency<T,N>:: operator/=(int_type i)
{
  value_ /= i;
   return * this;
}

template< class T,  int N>
void currency<T,N>::negate()
{
  value_ = -value_;
}

template< class T,  int N>
currency<T,N>& currency<T,N>:: operator++()
{
  ++value_;
   return * this;
}

template< class T,  int N>
currency<T,N> currency<T,N>:: operator++( int)
{
  currency result(* this);
  ++value_;
   return result;
}

template< class T,  int N>
currency<T,N>& currency<T,N>:: operator--()
{
  --value_;
   return * this;
}

template< class T,  int N>
currency<T,N> currency<T,N>:: operator--( int)
{
  currency result(* this);
  --value_;
   return result;
}

template< class T,  int N>
template< class CharT,  class Traits>
bool currency<T,N>::read(std::basic_istream<CharT,Traits>& strm)
{
  ioflags flags(strm);
  typename std::basic_istream<CharT, Traits>::sentry sentry(strm,  false);
   if (not sentry)
     return  false;

  std::ios_base::iostate error(std::ios_base::goodbit);
  std:: string digits;
  std::money_get<CharT>  constget(
      std::use_facet<std::money_get<CharT> >(strm.getloc()));
   get. get(std::istreambuf_iterator<CharT>(strm), std::istreambuf_iterator<CharT>(),
           false, strm, error, digits);

   if ((error & std::ios_base::failbit) !=  0)
     return  false;

  std::moneypunct<CharT>  const& punct(
      std::use_facet<std::moneypunct<CharT> >(strm.getloc()));

   //  Set fraction to the rightmost frac_digits() characters of digits.
  std:: string fraction(digits.substr(digits.size() - punct.frac_digits(), punct.frac_digits()));
   //  Set integer to the remainder of digits.
  std:: string integer(digits.substr( 0, digits.size() - punct.frac_digits()));

  std::istringstream fixed_stream(integer +  " . " + fraction);
   return value_.read(fixed_stream);
}

///  Read a currency value
///  @param strm The input stream
///  @param[out] c Store the value here
template< class T,  int N,  class Char,  class Traits>
std::basic_istream<Char, Traits>&  operator>>(std::basic_istream<Char, Traits>& strm, currency<T,N>& c)
{
   if (not c.read(strm))
    strm.setstate(strm.failbit);
   return strm;
}

///  Write a currency value
///  @param strm The output stream
///  @param c The value to write
template< class T,  int N,  class Char,  class Traits>
std::basic_ostream<Char, Traits>&  operator<<(std::basic_ostream<Char, Traits>& strm, currency<T,N> c)
{
  typename std::basic_ostream<Char, Traits>::sentry sentry(strm);
  strm << c.as_string();
   return strm;
}

///  Negate a currency value
template< class T,  int N>
currency<T,N>  operator-(currency<T,N> a)
{
  a.negate();
   return a;
}

///  Add currency values
///  @param a The left-hand operand
///  @param b The right-hand operand
template< class T,  int N>
currency<T,N>  operator+(currency<T,N> a, currency<T,N> b)
{
  a += b;
   return a;
}

///  Subtract currency values
///  @param a The left-hand operand
///  @param b The right-hand operand
template< class T,  int N>
currency<T,N>  operator-(currency<T,N> a, currency<T,N> b)
{
  a -= b;
   return a;
}

///  Multiply currency value and an integer
///  @param a The left-hand operand
///  @param b The right-hand operand
template< class T,  int N>
currency<T,N>  operator*(currency<T,N> a, T b)
{
  a *= b;
   return a;
}

///  Multiply currency value and an integer
///  @param a The left-hand operand
///  @param b The right-hand operand
template< class T,  int N>
currency<T,N>  operator*(T a, currency<T,N> b)
{
  b *= a;
   return b;
}

///  Divide currency value by an integer
///  @param a The left-hand operand
///  @param b The right-hand operand
template< class T,  int N>
currency<T,N>  operator/(currency<T,N> a, T b)
{
  a /= b;
   return a;
}

///  Divide currency values to yield a rational result.
///  @param n the numerator
///  @param d the denominator
template< class T,  int N>
rational<T>  operator/(currency<T,N> n, currency<T,N> d)
{
   //  Extract the underlying value of the fixed values. No adjustment
  
//  to scaling is needed because the numerator and denominator are
  
//  both scaled to the same amount.
   return rational<T>(n.value().value(), d.value().value());
}

///  Compare currency values for equality by comparing the underlying values.
///  @param a The left-hand operand
///  @param b The right-hand operand
template< class T,  int N>
bool  operator==(currency<T,N> a, currency<T,N> b)
{
   return a.value() == b.value();
}
///  Compare currency value and an integer for equality
///  @param a The left-hand operand
///  @param b The right-hand operand
template< class T,  int N>
bool  operator==(currency<T,N> a, T b)
{
   return a.value() == b;
}
///  Compare currency value and an integer for equality
///  @param a The left-hand operand
///  @param b The right-hand operand
template< class T,  int N>
bool  operator==(T a, currency<T,N> b)
{
   return a == b.value();
}

///  Compare currency values for inequality.
///  @param a The left-hand operand
///  @param b The right-hand operand
template< class T,  int N>
inline  bool  operator!=(currency<T,N> a, currency<T,N> b)
{
   return not (a == b);
}
///  Compare currency value and an integer for inequality
///  @param a The left-hand operand
///  @param b The right-hand operand
template< class T,  int N>
inline  bool  operator!=(currency<T,N> a, T b)
{
   return not (a == b);
}
///  Compare currency value and an integer for inequality
///  @param a The left-hand operand
///  @param b The right-hand operand
template< class T,  int N>
inline  bool  operator!=(T a, currency<T,N> b)
{
   return not (a == b);
}

///  Compare currency values for less-than by comparing the underlying values.
///  @param a The left-hand operand
///  @param b The right-hand operand
template< class T,  int N>
bool  operator<(currency<T,N> a, currency<T,N> b)
{
   return a.value() < b.value();
}
///  Compare a currency value and an integer for less-than.
///  @param a The left-hand operand
///  @param b The right-hand operand
template< class T,  int N>
bool  operator<(currency<T,N> a, T b)
{
   return a.value() < b;
}
///  Compare a currency value and an integer for less-than.
///  @param a The left-hand operand
///  @param b The right-hand operand
template< class T,  int N>
bool  operator<(T a, currency<T,N> b)
{
   return a < b.value();
}

///  Compare currency values for greater-than.
///  @param a The left-hand operand
///  @param b The right-hand operand
template< class T,  int N>
inline  bool  operator>(currency<T,N> a, currency<T,N> b)
{
   return b < a;
}
///  Compare a currency value and an integer for greater-than.
///  @param a The left-hand operand
///  @param b The right-hand operand
template< class T,  int N>
inline  bool  operator>(currency<T,N> a, T b)
{
   return b < a;
}
///  Compare a currency value and an integer for greater-than.
///  @param a The left-hand operand
///  @param b The right-hand operand
template< class T,  int N>
inline  bool  operator>(T a, currency<T,N> b)
{
   return b < a;
}

///  Compare currency values for less-than-or-equal.
///  @param a The left-hand operand
///  @param b The right-hand operand
template< class T,  int N>
inline  bool  operator<=(currency<T,N> a, currency<T,N> b)
{
   return not (b < a);
}
///  Compare a currency value and an integer for less-than-or-equal.
///  @param a The left-hand operand
///  @param b The right-hand operand
template< class T,  int N>
inline  bool  operator<=(currency<T,N> a, T b)
{
   return not (b < a);
}
///  Compare a currency value and an integer for less-than-or-equal.
///  @param a The left-hand operand
///  @param b The right-hand operand
template< class T,  int N>
inline  bool  operator<=(T a, currency<T,N> b)
{
   return not (b < a);
}

///  Compare currency values for greater-than-or-equal.
///  @param a The left-hand operand
///  @param b The right-hand operand
template< class T,  int N>
inline  bool  operator>=(currency<T,N> a, currency<T,N> b)
{
   return not (a < b);
}
///  Compare a currency value and an integer for greater-than-or-equal.
///  @param a The left-hand operand
///  @param b The right-hand operand
template< class T,  int N>
inline  bool  operator>=(currency<T,N> a, T b)
{
   return not (a < b);
}
///  Compare a currency value and an integer for greater-than-or-equal.
///  @param a The left-hand operand
///  @param b The right-hand operand
template< class T,  int N>
inline  bool  operator>=(T a, currency<T,N> b)
{
   return not (a < b);
}

#endif

fixed.hpp:

View Code
/* * @file fixed.hpp  */
/* * Listing 49-5. Changing fixed from a Class to a Class Template  */

#ifndef FIXED_HPP_
#define FIXED_HPP_

#include <cassert>
#include <cmath>
#include <iomanip>
#include <ios>
#include <istream>
#include <locale>
#include <ostream>
#include <sstream>
#include <stdexcept>
#include < string>

#include  " ioflags.hpp "

/* * @brief Implement a fixed-point number class template.
 * Values have @c N places after the decimal point.
 * All arithmetic follows the usual rules.
 
*/
template< class T,  int N>
class  fixed
{
public:
    typedef T value_type;                     /// < Type of the actual value

     static value_type  const places = N;       /// < number of decimal places
    static value_type const places10;         /// < 10<sup> places </sup>

    
///  Default constructor initializes to zero.
     fixed() : value_() {}

     ///  Construct from separate integer and fractional parts,
    
///  e.g., initialize to 123.45 with fixed(123, 45). Initialize
    
///  to 12.07 with fixed(12, 7).
     fixed(value_type integer, value_type fraction);

     ///  Construct from an integer with no fractional part.
     fixed(value_type integer);

     ///  Construct by rounding off a floating point number.
     fixed( double value)
    : value_(static_cast<value_type>(value * places10 + (value <  0 ? - 0.5 :  0.5)))
    {}

     ///  Convert to a string.
    
///  @returns a string representation of the value, e.g., "123.04"
    std:: string as_string()  const;
     ///  Read from a stream.
    
///  Overwrite this value with the value read from the stream.
    
///  @param strm the stream to read
    
///  @returns true for success or false for failure
    template< class Char,  class Traits>
     bool read(std::basic_istream<Char, Traits>& strm);
     ///  Convert to long double.
     double as_long_double()  const {  return static_cast< long  double>(value()) / places10; }
     ///  Convert to double.
     double as_double()  const {  return static_cast< double>(value()) / places10; }
     ///  Convert to float
     float as_float()  const {  return static_cast< float>(value()) / places10; }
     ///  Return just the integer part, rounded off to the nearest integer.
    
///  If the value lies equidistant between two integers, round even
    
///  numbers up and odd numbers down (banker's rounding).
    value_type round()  const;

     ///  Return the integer part (which is the same as trunc()).
    value_type integer()  const {  return value() / places10; }
     ///  Return the fractional part, e.g., 3 for 12.03
    value_type fraction()  const;

     ///  Addition assignment operator
     fixedoperator+=( fixed f);
     ///  Subtraction assignment operator
     fixedoperator-=( fixed f);
     ///  Multiplication assignment operator
     fixedoperator*=( fixed f);
     ///  Division assignment operator
     fixedoperator/=( fixed f);

     ///  Negate this value.
     void negate();

     ///  Pre-increment
     fixedoperator++();
     ///  Post-increment
     fixed  operator++( int);
     ///  Pre-decrement
     fixedoperator--();
     ///  Post-decrement
     fixed  operator--( int);

     ///  Return the internal value.
    value_type value()     const {  return value_; }
private:
     ///  Reduce frac to the range [0, places10) by discarding digits to the right.
    value_type reduce(value_type frac);
    value_type value_;
};

template< class T,  int N>
typename  fixed<T,N>::value_type  const  fixed<T,N>::places10 = static_cast<typename  fixed<T,N>::value_type>(std::pow( 10.0double(places)));

//  Construct a fixed value from an integer part and a fraction part
template< class T,  int N>
fixed<T,N>:: fixed(value_type integer, value_type fraction)
{
   if (fraction < T())
     throw std::invalid_argument( " negative fraction not allowed ");
  fraction = reduce(fraction);
   if (integer < T())
    value_ = integer * places10 - fraction;
   else
    value_ = integer * places10 + fraction;
}

//  Construct a fixed value from an integer part with no fraction
template< class T,  int N>
fixed<T,N>:: fixed(value_type integer)
: value_(integer * places10)
{}

//  Get the fraction part
template< class T,  int N>
typename  fixed<T,N>::value_type  fixed<T,N>::fraction()
const
{
   return std::abs(value()) % places10;
}

///  Reduce the fractional part to the range [0, places10).
///  Imagine frac has the format F(G(XY*)?)?.
///  The resulting value is FH, where H == 0 if G is absent,
///  or H == G+1 if X==5 and Y* == 0* and G is odd, or
///  H == G+1 if X>5 or X==5 and Y*>0*, else H == G.
///  In other words, check that frac ends with only zero digits,
///  then a 5, then two more digits (searching from least-significant
///  to most-significant). If so, implement banker's rounding.
///  Otherwise, round GXY* to the nearest value (G+1 or G).
template< class T,  int N>
typename  fixed<T,N>::value_type  fixed<T,N>::reduce(value_type frac)
{
   //  First scan for zero digits on the right.
  value_type f(frac);
   while (f >= places10* 10 and f %  10 ==  0)
  {
    f /=  10;
  }

   if (f >= places10* 10)
  {
     int x( 0);
     //  Loop ended because a non-zero digit was seen so Y* > 0.
    
//  Discard the remaining digits, but keep track of the last
    
//  digit to be processed (X).
     while (f >= places10)
    {
      x = f %  10;
      f /=  10;
    }
     //  Round up if the last digit (X) is 5 or more
     if (x >=  5)
      ++f;
     return f;
  }
   //  Else all digits so far are zero. Check how many digits there were,
  
//  that is, check whether G, and X at least are present.
   else  if (f >= places10)
  {
     //  Yes, G and X are present. If X == 5, implement banker's rounding.
    
//  Otherwise, round to nearest.
     int x(f %  10);
    f /=  10;
    assert(f < places10);
     if (x ==  5)
    {
       //  Yes, so implement banker's rounding.
       if (f %  2 !=  0)
        ++f;
       return f;
    }
     else  if (x <  5)
    {
       //  Round down.
       return f;
    }
     else
    {
       //  Round up.
       return f +  1;
    }
  }
   //  Not enough digits, so nothing to round.
  assert(frac < places10);
   return frac;
}

//  Round off to nearest integer.
template< class T,  int N>
typename  fixed<T,N>::value_type  fixed<T,N>::round()
const
{
   const value_type frac(fraction());
   int adjust(value() <  0 ? - 1 : + 1);
   if (frac > places10/ 2)
     return integer()+adjust;
   else  if (frac < places10/ 2)
     return integer();
   else  if (integer() %  2 ==  0)
     return integer();
   else
     return integer()+adjust;
}

//  Convert to a string using fixed-point notation.
template< class T,  int N>
std:: string  fixed<T,N>::as_string()
const
{
  std::ostringstream  out;
   out << integer() <<  ' . '
      << std::setfill( ' 0 ') << std::setw(places) << fraction();
   return  out.str();
}

template< class T,  int N>
fixed<T,N>&  fixed<T,N>:: operator+=( fixed f)
{
  value_ += f.value();
   return * this;
}

template< class T,  int N>
fixed<T,N>&  fixed<T,N>:: operator-=( fixed f)
{
  value_ -= f.value();
   return * this;
}

template< class T,  int N>
fixed<T,N>&  fixed<T,N>:: operator*=( fixed f)
{
  value_ = (value_ * f.value()) / places10;
   return * this;
}

template< class T,  int N>
fixed<T,N>&  fixed<T,N>:: operator/=( fixed f)
{
  value_ = (value_ * places10) / f.value();
   return * this;
}

template< class T,  int N>
void  fixed<T,N>::negate()
{
  value_ = -value_;
}

template< class T,  int N>
fixed<T,N>&  fixed<T,N>:: operator++()
{
  value_ += places10;
   return * this;
}

template< class T,  int N>
fixed<T,N>  fixed<T,N>:: operator++( int)
{
   fixed result(* this);
  ++* this;
   return result;
}

template< class T,  int N>
fixed<T,N>&  fixed<T,N>:: operator--()
{
  value_ -= places10;
   return * this;
}

template< class T,  int N>
fixed<T,N>  fixed<T,N>:: operator--( int)
{
   fixed result(* this);
  --* this;
   return result;
}

template< class T,  int N>
template< class Char,  class Traits>
bool  fixed<T,N>::read(std::basic_istream<Char, Traits>& strm)
{
  ioflags flags(strm);

  value_type integer;
   char  decimal;
   if (not (strm >> integer))
     return  false;
  strm.unsetf(std::ios_base::skipws);
   if (not (strm >>  decimal) or  decimal !=  ' . ')
  {
     //  Just an integer is fine. Push back the non-decimal character,
    
//  if there is one, and reset the stream flags to show that
    
//  reading the fixed value succeeded.
    strm.unget();
    strm.clear(strm.rdstate() & ~strm.failbit);
    value_ = integer * places10;
     return  true;
  }
   else
  {
    value_type fraction( 0);
     char c;
     int p( 0);
     //  Read one extra place for round-off.
     for (;
          p != places+ 1 and strm >> c and std::isdigit(c, strm.getloc());
          ++p)
    {
      fraction = fraction *  10 + (c -  ' 0 ');
    }
     //  Pad out to the requisite number of decimal places.
     for (; p < places; ++p)
      fraction = fraction *  10;
     //  If the loop terminated because the maximum number of decimal
    
//  places were read, keep reading the stream to discard excees digits.
     while (strm and std::isdigit(c, strm.getloc()))
      strm >> c;
     //  Push back the last, non-digit character read from the stream.
    
//  If the stream reached EOF, unget() is harmless.
    strm.unget();
     //  Clear failbit because even if reading a character or whatever
    
//  failed, reading the fixed value did not.
    strm.clear(strm.rdstate() & ~strm.failbit);
    fraction = reduce(fraction);
     if (integer <  0)
      value_ = integer * places10 - fraction;
     else
      value_ = integer * places10 + fraction;
  }
   return  true;
}

///  Read a fixed value
template< class T,  int N,  class Char,  class Traits>
std::basic_istream<Char, Traits>&  operator>>(std::basic_istream<Char, Traits>& strm,  fixed<T,N>& f)
{
   if (not f.read(strm))
    strm.setstate(strm.failbit);
   return strm;
}

///  Write a fixed value
template< class T,  int N,  class Char,  class Traits>
std::basic_ostream<Char, Traits>&  operator<<(std::basic_ostream<Char, Traits>& strm,  fixed<T,N> f)
{
  strm << f.as_string();
   return strm;
}

///  Add fixed values
template< class T,  int N>
fixed<T,N>  operator+( fixed<T,N> a,  fixed<T,N> b)
{
  a += b;
   return a;
}

///  Subtract fixed values
template< class T,  int N>
fixed<T,N>  operator-( fixed<T,N> a,  fixed<T,N> b)
{
  a -= b;
   return a;
}

///  Multiply fixed values
template< class T,  int N>
fixed<T,N>  operator*( fixed<T,N> a,  fixed<T,N> b)
{
  a *= b;
   return a;
}

///  Divide fixed values
template< class T,  int N>
fixed<T,N>  operator/( fixed<T,N> a,  fixed<T,N> b)
{
  a /= b;
   return a;
}

///  Negate a fixed value
template< class T,  int N>
fixed<T,N>  operator-( fixed<T,N> a)
{
  a.negate();
   return a;
}

///  Compare fixed values for equality by comparing the underlying values.
template< class T,  int N>
bool  operator==( fixed<T,N> a,  fixed<T,N> b)
{
   return a.value() == b.value();
}
///  Compare fixed values for equality by comparing the value wih an integer.
template< class T,  int N>
bool  operator==(T a,  fixed<T,N> b)
{
   return a == b.value();
}
///  Compare fixed values for equality by comparing the value wih an integer.
template< class T,  int N>
bool  operator==( fixed<T,N> a, T b)
{
   return a.value() == b;
}

///  Compare fixed values for inequality by comparing the underlying values.
template< class T,  int N>
bool  operator!=( fixed<T,N> a,  fixed<T,N> b)
{
   return not (a == b);
}
///  Compare fixed values for inequality by comparing the value wih an integer.
template< class T,  int N>
bool  operator!=(T a,  fixed<T,N> b)
{
   return not (a == b);
}
///  Compare fixed values for inequality by comparing the value wih an integer.
template< class T,  int N>
bool  operator!=( fixed<T,N> a, T b)
{
   return not (a == b);
}

///  Compare fixed values for less-than by comparing the underlying values.
template< class T,  int N>
bool  operator<( fixed<T,N> a,  fixed<T,N> b)
{
   return a.value() < b.value();
}
///  Compare fixed values for less-than by comparing the value wih an integer.
template< class T,  int N>
bool  operator<(T a,  fixed<T,N> b)
{
   return a < b.value();
}
///  Compare fixed values for less-than by comparing the value wih an integer.
template< class T,  int N>
bool  operator<( fixed<T,N> a, T b)
{
   return a.value() < b;
}

///  Compare fixed values for greater-than by comparing the underlying values.
template< class T,  int N>
bool  operator>( fixed<T,N> a,  fixed<T,N> b)
{
   return b < a;
}
///  Compare fixed values for greater-than by comparing the value wih an integer.
template< class T,  int N>
bool  operator>(T a,  fixed<T,N> b)
{
   return b < a;
}
///  Compare fixed values for greater-than by comparing the value wih an integer.
template< class T,  int N>
bool  operator>( fixed<T,N> a, T b)
{
   return b < a;
}

///  Compare fixed values for less-than-or-equal by comparing the underlying values.
template< class T,  int N>
bool  operator<=( fixed<T,N> a,  fixed<T,N> b)
{
   return not (b < a);
}
///  Compare fixed values for less-than-or-equal by comparing the value wih an integer.
template< class T,  int N>
bool  operator<=(T a,  fixed<T,N> b)
{
   return not (b < a);
}
///  Compare fixed values for less-than-or-equal by comparing the value wih an integer.
template< class T,  int N>
bool  operator<=( fixed<T,N> a, T b)
{
   return not (b < a);
}

///  Compare fixed values for greater-than-or-equal by comparing the underlying values.
template< class T,  int N>
bool  operator>=( fixed<T,N> a,  fixed<T,N> b)
{
   return not (a < b);
}
///  Compare fixed values for greater-than-or-equal by comparing the value wih an integer.
template< class T,  int N>
bool  operator>=(T a,  fixed<T,N> b)
{
   return not (a < b);
}
///  Compare fixed values for greater-than-or-equal by comparing the value wih an integer.
template< class T,  int N>
bool  operator>=( fixed<T,N> a, T b)
{
   return not (a < b);
}

#endif

gcd.hpp:

View Code
#include  " gcd.hpp "

int gcd( int n,  int m)
{
   if (n <  0)
    n = -n;
   while (m !=  0) {
     int tmp(n % m);
    n = m;
    m = tmp;
  }
   return n;
}

gcd.cpp:

View Code
#ifndef GCD_HPP_
#define GCD_HPP_

///  Compute greatest-common-denominator.
///  @param n
///  @param m
int gcd( int n,  int m);

#endif

ioflags.hpp:

View Code
#ifndef IOFLAGS_HPP_
#define IOFLAGS_HPP_

/* * @file
 * @brief Save and restore I/O stream flags.
 
*/

/* * Save and restore I/O stream flags.
 * When a function needs to temporarily alter an I/O stream flags,
 * simply define an object of type @c ioflags. Set whatever flags
 * you want. When the block exits or function returns, the
 * original flags are restored.
 
*/

class ioflags
{
public:
   ///  Save the formatting flags from @p stream.
  
///  @param stream The stream that will have its flags modified and restored.
  ioflags(std::basic_ios< char>& stream) : stream_(stream), flags_(stream.flags()) {}
   ///  Restore the formatting flags.
  ~ioflags() { stream_.flags(flags_); }
private:
  std::basic_ios< char>& stream_;
  std::ios_base::fmtflags flags_;
};

#endif

rational.hpp:

View Code
#ifndef RATIONAL_HPP_
#define RATIONAL_HPP_

#include <istream>
#include <limits>
#include <ostream>
#include <sstream>
#include <stdexcept>
#include < string>

#include  " gcd.hpp "
#include  " ioflags.hpp "

///  Represent a rational number (fraction) as a numerator and denominator.
template< class T>
class rational
{
public:
   ///  Convenience typedef for the integral type of the numerator and denominator.
  typedef T value_type;
   ///  Exception class if the denominator is ever zero.
   class zero_denominator :  public std::logic_error
  {
   public:
     ///  Construct the exception object.
    zero_denominator(std:: string  const& what) : logic_error(what) {}
  };

   ///  Default constructor and constructor from a single value.
  
///  As a default constructor, initializes to zero.
  
///  Otherwise, initializes to the integer @p num.
  
///  @param num The integer value to use as the initial value
  rational(value_type num =  0): numerator_(num), denominator_( 1) {}
   ///  Construct a rational number
  
///  @param num numerator
  
///  @param den denominator
  
///  @throws zero_denominator if @p den == 0
  rational(value_type num, value_type den);
   ///  Initialize the rational number with an approximation of @p r
  
///  @param r the initial value
  rational( double r);
   ///  Copy from a different type of rational.
  template< class U>
  rational(rational<U>  const& that);

   ///  Return the numerator
  value_type numerator()               const {  return numerator_; }
   ///  Return the denominator
  value_type denominator()             const {  return denominator_; }
   ///  Convert the rational number to another type, especially floating-point.
  template< class U>
  U  as()  const {  return static_cast<U>(numerator()) / denominator(); }

   ///  Assignment of an integer
  rational&  operator=(value_type);  //  optimization to avoid an unneeded call to reduce()

   ///  Assignment of a rational with a different size.
  template< class U>
  rational&  operator=(rational<U>  const& rhs);

   ///  Addition assignment operator
  rational&  operator+=(rational  const& rhs);
   ///  Addition assignment operator
  rational&  operator+=(value_type  const& rhs);

   ///  Subtraction assignment operator
  rational&  operator-=(rational  const& rhs);
   ///  Subtraction assignment operator
  rational&  operator-=(value_type  const& rhs);

   ///  Multiplication assignment operator
  rational&  operator*=(rational  const& rhs);
   ///  Multiplication assignment operator
  rational&  operator*=(value_type  const& rhs);

   ///  Division assignment operator
  rational&  operator/=(rational  const& rhs);
   ///  Division assignment operator
  rational&  operator/=(value_type  const& rhs);

   ///  Pre-increment
  rational&  operator++();
   ///  Pre-decrement
  rational&  operator--();
   ///  Post-increment
  rational  operator++( int);
   ///  Post-decrement
  rational  operator--( int);

private:
   ///  Reduce the numerator and denominator by their GCD.
   void reduce();
   ///  Reduce the numerator and denominator, and normalize the signs of both,
  
///  that is, ensure denominator is not negative.
   void normalize();
   ///  Scale an integer of type @p U to the value_type. If @p U has more
  
///  digits than @p value_type shift @p value to the right.
  template< class U>
  value_type scale(U value);

  value_type numerator_;
  value_type denominator_;
};

template< class T>
rational<T>::rational(value_type num, value_type den)
: numerator_(num),
  denominator_(den == value_type() ?  throw zero_denominator( " zero denominator ") : den)
{
  normalize();
}

template< class T>
rational<T>::rational( double r)
: numerator_(static_cast<T>(r /  100000)), denominator_(static_cast<T>( 100000))
{}

template< class T>
template< class U>
rational<T>::rational(rational<U>  const& that)
: numerator_(scale<U>(that.numerator())), denominator_(scale<U>(that.denominator()))
{
  reduce();
}

template< class T>
template< class U>
T rational<T>::scale(U value)
{
   if (std::numeric_limits<T>::digits >= std::numeric_limits<U>::digits)
     return T(value);
   else
     return T(value >> (std::numeric_limits<U>::digits - std::numeric_limits<T>::digits));
}

template< class T>
void rational<T>::normalize()
{
   if (denominator_ < value_type())
  {
    denominator_ = -denominator_;
    numerator_ = -numerator_;
  }
  reduce();
}

template< class T>
void rational<T>::reduce()
{
  value_type div(gcd(numerator(), denominator()));
   if (div == value_type())
     throw zero_denominator( " zero denominator ");
  numerator_ /= div;
  denominator_ /= div;
}

template< class T>
rational<T>& rational<T>:: operator=(T num)
{
  numerator_ = num;
  denominator_ = value_type( 1);
   return * this;
}

template< class T>
template< class U>
rational<T>& rational<T>:: operator=(rational<U>  const& rhs)
{
  numerator_ = scale<U>(rhs.numerator());
  denominator_ = scale<U>(rhs.denominator());
  reduce();
   return * this;
}

template< class T>
rational<T>& rational<T>:: operator+=(rational  const& rhs)
{
  numerator_ = numerator() * rhs.denominator() + rhs.numerator() * denominator();
  denominator_ *= rhs.denominator();
  reduce();
   return * this;
}

template< class T>
rational<T>& rational<T>:: operator+=(value_type  const& rhs)
{
  numerator_ = numerator() + rhs * denominator();
  reduce();
   return * this;
}

template< class T>
rational<T>& rational<T>:: operator-=(rational  const& rhs)
{
  numerator_ = numerator() * rhs.denominator() - rhs.numerator() * denominator();
  denominator_ *= rhs.denominator();
  reduce();
   return * this;
}

template< class T>
rational<T>& rational<T>:: operator-=(value_type  const& rhs)
{
  numerator_ = numerator() - rhs * denominator();
  reduce();
   return * this;
}

template< class T>
rational<T>& rational<T>:: operator*=(rational  const& rhs)
{
  numerator_ *= rhs.numerator();
  denominator_ *= rhs.denominator();
  reduce();
   return * this;
}

template< class T>
rational<T>& rational<T>:: operator*=(value_type  const& rhs)
{
  numerator_ *= rhs;
  reduce();
   return * this;
}

template< class T>
rational<T>& rational<T>:: operator/=(rational  const& rhs)
{
   if (rhs.numerator() == value_type())
     throw zero_denominator( " divide by zero ");
  numerator_ *= rhs.denominator();
  denominator_ *= rhs.numerator();
  normalize();
   return * this;
}

template< class T>
rational<T>& rational<T>:: operator/=(value_type  const& rhs)
{
   if (rhs == value_type())
     throw zero_denominator( " divide by zero ");
  denominator_ *= rhs;
  normalize();
   return * this;
}

template< class T>
rational<T>& rational<T>:: operator++()
{
  numerator_ += denominator();
   return * this;
}

template< class T>
rational<T> rational<T>:: operator++( int)
{
  rational result(* this);
  ++* this;
   return result;
}

template< class T>
rational<T>& rational<T>:: operator--()
{
  numerator_ -= denominator();
   return * this;
}

template< class T>
rational<T> rational<T>:: operator--( int)
{
  rational result(* this);
  --* this;
   return result;
}

///  Negate a rational number
template< class T>
rational<T>  operator-(rational<T>  const& r)
{
   return rational<T>(-r.numerator(), r.denominator());
}

template< class T>
rational<T> absval(rational<T>  const& r)
{
   using  namespace std;
   return rational<T>(abs(r.numerator()), r.denominator());
}

///  Addition
template< class T>
rational<T>  operator+(rational<T> lhs, rational<T>  const& rhs)
{
  lhs += rhs;
   return lhs;
}

///  Addition
template< class T>
rational<T>  operator+(rational<T> lhs, T  const& rhs)
{
  lhs += rhs;
   return lhs;
}

///  Addition
template< class T>
rational<T>  operator+(T  const& lhs, rational<T> rhs)
{
  rhs += lhs;
   return rhs;
}

///  Subtraction
template< class T>
rational<T>  operator-(rational<T> lhs, rational<T>  const& rhs)
{
  lhs -= rhs;
   return lhs;
}

///  Subtraction
template< class T>
rational<T>  operator-(rational<T> lhs, T  const& rhs)
{
  lhs -= rhs;
   return lhs;
}

///  Subtraction
template< class T>
rational<T>  operator-(T  const& lhs, rational<T> rhs)
{
   //  Gotta be a little tricky.
  rhs += -lhs;
   return -rhs;
}

///  Multiplication
template< class T>
rational<T>  operator*(rational<T> lhs, rational<T>  const& rhs)
{
  lhs *= rhs;
   return lhs;
}

///  Multiplication
template< class T>
rational<T>  operator*(rational<T> lhs, T  const& rhs)
{
  lhs *= rhs;
   return lhs;
}

///  Multiplication
template< class T>
    rational<T>  operator*(T  const& lhs, rational<T> rhs)
{
  rhs *= lhs;
   return rhs;
}

///  Division
template< class T>
rational<T>  operator/(rational<T> lhs, rational<T>  const& rhs)
{
  lhs /= rhs;
   return lhs;
}

///  Division
template< class T>
rational<T>  operator/(rational<T> lhs, T  const& rhs)
{
  lhs /= rhs;
   return lhs;
}

///  Division
template< class T>
rational<T>  operator/(T  const& lhs, rational<T> rhs)
{
   return rational<T>(lhs * rhs.denominator(), rhs.numerator());
}


///  Equality comparison
template< class T,  class U>
bool  operator==(rational<T>  const& a, rational<U>  const& b)
{
   return a.numerator() == b.numerator() and
         a.denominator() == b.denominator();
}

///  Equality comparison
template< class T>
bool  operator==(rational<T>  const& lhs, T rhs)
{
   return lhs.denominator() ==  1 and
         lhs.numerator()   == rhs;
}

///  Equality comparison
template< class T>
bool  operator==(T lhs, rational<T>  const& rhs)
{
   return rhs.denominator() ==  1 and
         rhs.numerator()   == lhs;
}

///  Less-than comparison
template< class T>
bool  operator<(rational<T>  const& a, rational<T>  const& b)
{
   return a.numerator() * b.denominator() < b.numerator() * a.denominator();
}

///  Less-than comparison
template< class T>
bool  operator<(rational<T>  const& a, T  const& b)
{
   return a.numerator() < b * a.denominator();
}

///  Less-than comparison
template< class T>
bool  operator<(T  const& a, rational<T>  const& b)
{
   return a * b.denominator() < b.numerator();
}

///  Inequality comparison
template< class T,  class U>
inline  bool  operator!=(rational<T>  const& a, rational<U>  const& b)
{
   return not (a == b);
}

///  Inequality comparison
template< class T>
inline  bool  operator!=(rational<T>  const& a, T b)
{
   return not (a == b);
}

///  Inequality comparison
template< class T>
inline  bool  operator!=(T a, rational<T>  const& b)
{
   return not (a == b);
}

///  Less-than-or-equal comparison
template< class T>
inline  bool  operator<=(rational<T>  const& a, rational<T>  const& b)
{
   return not (b < a);
}

///  Less-than-or-equal comparison
template< class T>
inline  bool  operator<=(rational<T>  const& a, T  const& b)
{
   return not (b < a);
}

///  Less-than-or-equal comparison
template< class T>
inline  bool  operator<=(T  const& a, rational<T>  const& b)
{
   return not (b < a);
}

///  Greater-than comparison
template< class T>
inline  bool  operator>(rational<T>  const& a, rational<T>  const& b)
{
   return b < a;
}

///  Greater-than comparison
template< class T>
inline  bool  operator>(rational<T>  const& a, T  const& b)
{
   return b < a;
}

///  Greater-than comparison
template< class T>
inline  bool  operator>(T  const& a, rational<T>  const& b)
{
   return b < a;
}

///  Greater-than-or-equal comparison
template< class T>
inline  bool  operator>=(rational<T>  const& a, rational<T>  const& b)
{
   return not (b > a);
}

///  Greater-than-or-equal comparison
template< class T>
inline  bool  operator>=(rational<T>  const& a, T  const& b)
{
   return not (b > a);
}

///  Greater-than-or-equal comparison
template< class T>
inline  bool  operator>=(T  const& a, rational<T>  const& b)
{
   return not (b > a);
}

///  Input operator
template< class T,  class Char,  class Traits>
std::basic_istream<Char, Traits>&  operator>>(std::basic_istream<Char, Traits>&  in, rational<T>& rat)
{
  typename std::basic_istream<Char, Traits>::sentry sentry( infalse);
  ioflags flags( in);

  T n = T();
   if (not ( in >> n))
     //  Error reading the numerator.
     return  in;

   in >> std::noskipws;
   char sep( ' \0 ');
   if (not ( in >> sep))
     //  Error reading the separator character.
     return  in;
   else  if (sep !=  ' / ')
  {
     //  Push sep back into the input stream, so the next input operation
    
//  will read it.
     in.unget();
    rat = n;
     return  in;
  }
   else
  {
    T d = T();
     if ( in >> d)
       //  Successfully read numerator, separator, and denominator.
      rat = rational<T>(n, d);
  }

   return  in;
}

///  Output operator
template< class T,  class Char,  class Traits>
std::basic_ostream<Char, Traits>&  operator<<(std::basic_ostream<Char, Traits>&  out, rational<T>  const& rat)
{
  typename std::basic_ostream<Char, Traits>::sentry sentry( out);
  std::ostringstream stream;
  stream << rat.numerator() <<  ' / ' << rat.denominator();
   out << stream.str();
   return  out;
}

#endif

test.cpp:

View Code
/* * @file test.cpp  */
/* * Listing 45-1. Testing the fixed Class  */
#include <iostream>
#include <istream>
#include <locale>
#include <ostream>
#include <sstream>
#include <stdexcept>

#include  " test.hpp "
#include  " currency.hpp "

int main( int argc,  char** argv)
{
   if (argc >=  2)
    std::locale:: global(std::locale(argv[ 1]));
   else
    std::locale:: global(std::locale( ""));
  std::cin.imbue(std::locale());
  std::cout.imbue(std::locale());
  typedef currency< long, 4> currency4;
  typedef currency< long, 2> currency2;
  currency2 c1;
  TEST(c1.value().value() ==  0);
  currency2 c2( 1L);
  TEST(c2.value().value() ==  100);
  currency2 c3( 31416);
  TEST(c3.value().value() ==  314);
  currency2 c4( 6275);
  TEST(c4.value().value() ==  628);
  currency2 c5( 5279);
  TEST(c5.value().value() ==  528);
  TEST(c3 + c3 == c1 + c4);
  TEST(c3 + c3 <= c1 + c4);
  TEST(c3 + c3 >= c1 + c4);
  TEST(c1 < c2);
  TEST(c1 <= c2);
  TEST(c1 != c2);
  TEST(c2 > c1);
  TEST(c2 >= c1);
  TEST(c2 != c1);
  TEST(c2 /  2L == currency2( 050));

  TEST(c4 - c5 == c2);
  TEST(c3 *  2L == c4);
  TEST(c4 /  2L == c3);
  c5 += c2;
  TEST(c5 == c4);
  c5 /=  2L;
  TEST(c3 == c5);
  c3 *=  2L;
  TEST(c3 == c4);
  c3 -= c5;
  TEST(c3 == c5);

  TEST(-c4 == c1 - c4);
  TEST(-(-c4) == c4);
  TEST(c3 + c5 == --c4 + c2);
  TEST(c3 + c5 == c4 + c2);
  TEST(c3 + c5 == c4-- + c2);
  TEST(c3 + c5 == c4 + c2 + c2);
  TEST(c3 + c5 == ++c4 + c2);
  TEST(c3 + c5 == c4 + c2);
  TEST(c3 + c5 == c4++ + c2);
  TEST(c3 + c5 == c4);

  c2 *=  2L;
  TEST(c4 / c2 == rational< long>( 314100));
  TEST((c4 /=  2L) == c5);
  TEST(c4 == c5);

  TEST(c4.as_string() ==  " 3.14 ");
  TEST(c4.integer() ==  3);
  c4 += currency2(- 1, 8);
  TEST((c4 == currency2( 2.06)));
  TEST(c4.integer() ==  2);
  TEST(c4.round() ==  2);
  c4 += c2 /  2L;
  TEST(c4.round() ==  3);

  TEST(c3.integer() ==  3);
  TEST((-c3).integer() == - 3);
  TEST(c3.fraction() ==  14);
  TEST((-c3).fraction() ==  14);

  TEST(currency4( 7, 4999).round() ==  7L);
  TEST(currency4( 7, 5000).round() ==  8L);
  TEST(currency4( 7, 5001).round() ==  8L);
  TEST(currency4( 7, 4999).round() ==  7L);
  TEST(currency4( 8, 5000).round() ==  8L);
  TEST(currency4( 8, 5001).round() ==  9L);

  TEST(currency4( 123, 2345500) == currency4( 123, 2346));
  TEST(currency4( 123, 2345501) == currency4( 123, 2346));
  TEST(currency4( 123, 2345499) == currency4( 123, 2345));
  TEST(currency4( 123, 2346500) == currency4( 123, 2346));
  TEST(currency4( 123, 2346501) == currency4( 123, 2347));
  TEST(currency4( 123, 2346499) == currency4( 123, 2346));
  TEST(currency4( 123, 2346400) == currency4( 123, 2346));
  TEST(currency4( 123, 2346600) == currency4( 123, 2347));

  TEST(currency4(- 3.14159265).value().value() == - 31416L);
  TEST(currency4( 123, 456789).value().value() ==  1234568L);
  TEST(currency4( 123, 4).value().value() ==  1230004L);
  TEST(currency4(- 10, 1111).value().value() == - 101111L);

  std::ostringstream  out;
  c3 = currency2( 314);
   out << std::showbase << c3 <<  "  3.14  " << currency2(- 10, 12) <<  "  3.00 421.40 end ";
  currency2 c6;
  std::istringstream  in( out.str());
  TEST( in >> c6);
  TEST(c6 == c3);
  c6 = currency2();
  TEST( in >> c6);
  TEST(c6 == c3);
  TEST( in >> c6);
  TEST(c6.value() == - 1012L);
  TEST( in >> c6);
  TEST(c6.value() ==  300L);
  TEST( in >> c6);
  TEST(c6.value() ==  42140L);
  TEST(not ( in >> c6));

  TEST(currency2( 31.59265) == currency2( 3159));
  TEST(currency2( 31.595) == currency2( 3160));

   //  Adjust the following test to match your native locale.
  currency2 big( 123456789);
  TEST(big.as_string() ==  " 1,234,567.89 ");

   bool okay( false);
   try {
    currency2 c7( 1, - 1);
  }  catch (std::invalid_argument  const& ex) {
    okay =  true;
  }  catch (std::exception  const& ex) {
    std::cerr <<  " wrong exception:  " << ex.what() <<  ' \n ';
  }
  TEST(okay);
}

test.hpp:

View Code
#ifndef TEST_HPP_
#define TEST_HPP_

#include <exception>
#include <iostream>
#include <ostream>

//  For internal use by the TEST() macro.
//  Turn the macro argument into a character string literal
#define TEST_STRINGIFY(x) #x

//  For internal use by the TEST() macro.
//  Report a test failure.
inline  void test_failed( char  const* expr,  char  const* file,  int line)
{
   std::cerr << file <<  " , line  " << line <<  " : test failed:  " << expr <<  ' \n ';
}

//  For internal use by the TEST() macro
//  Run a test. Report a failure if the condition is false or
inline  void test_run( bool condition,  char  const* expr,  char  const* file,  int line)
{
   if (not condition)
    test_failed(expr, file, line);
}

//  For internal use by the TEST() macro.
//  Report an exception.
inline  void test_exception(std::exception  const& ex,  char  const* expr,  char  const* file,  int line)
{
  std:: string msg( expr );
  msg +=  "  threw an exception:  ";
  msg += ex.what();
  test_failed(msg.c_str(), file, line);
}

///  Test a condition, @p x.
///  If @p x evaluates to @c true the test passes.
///  If not, the test fails, and a message is printed to @c cerr.
///  The text of @p x, plus the file name and line number are printed.
///
///  See Boost.Test for a real test framework
///
///  @param x A condition to test; the condition must be able to be converted implicitly to @c bool.
#define TEST(x) \
try {\
  test_run(x, TEST_STRINGIFY(x), __FILE__, __LINE__);\
}\
catch(std::exception  const& ex)\
{\
  test_exception(ex, TEST_STRINGIFY(x), __FILE__, __LINE__);\
}

#endif

第56讲 指针

1. 拓扑排序,简单make程序

 

TOPOLOGICAL_SORT_HPP:
View Code
/* * @file list5601.cpp  */
/* * Listing 56-1. Topological Sort of a Directed Acyclic Graph  */
#ifndef TOPOLOGICAL_SORT_HPP_
#define TOPOLOGICAL_SORT_HPP_

#include <queue>
#include <stdexcept>

///  Helper function for topological_sort().
///  Finds all the nodes in the graph with no incoming edges,
///  that is, with empty values. Removes each one from the graph
///  and adds it to the set @p nodes.
///  @param[in,out] graph A map of node/set pairs
///  @param[in,out] nodes A queue of nodes with no incoming edges
template< class Graph,  class Nodes>
void topsort_clean_graph(Graph& graph, Nodes& nodes)
{
   for (typename Graph::iterator iter(graph.begin()); iter != graph.end(); )
  {
     if (iter->second.empty())
    {
      nodes.push(iter->first);
      graph.erase(iter++);   //  advance iterator before erase invalidates it
    }
     else
      ++iter;
  }
}

///  Topological sort of a directed acyclic graph.
///  A graph is a map keyed by nodes, with sets of nodes as values.
///  Edges run from values to keys. The sorted list of nodes
///  is copied to an output iterator in reverse order.
///  @param graph The graph
///  @param sorted The output iterator
///  @throws std::runtime_error if the graph contains a cycle
///  @pre Graph::key_type == Graph::mapped_type::key_type
template< class Graph,  class OutIterator>
void topological_sort(Graph graph, OutIterator sorted)
{
  std::queue<typename Graph::key_type> nodes;
   //  Start with the set of nodes with no incoming edges.
  topsort_clean_graph(graph, nodes);

   while (not nodes.empty())
  {
     //  Grab the first node to process, output it to sorted,
    
//  and remove it from the graph.
    typename Graph::key_type n(nodes.front());
    nodes.pop();
    *sorted = n;
    ++sorted;

     //  Erase n from the graph
     for (typename Graph::iterator iter(graph.begin()); iter != graph.end(); ++iter)
    {
      iter->second.erase(n);
    }
     //  After removing n, find any nodes that no longer
    
//  have any incoming edges.
    topsort_clean_graph(graph, nodes);
  }
   if (not graph.empty())
     throw std::invalid_argument( " Dependency graph contains cycles ");
}

#endif  //  TOPOLOGICAL_SORT_HPP_

 MAIN.cpp:

 

View Code
/* * @file list5602.cpp  */
/* * Listing 56-2. First Draft of the Pseudo-Make Program  */
#include <algorithm>
#include <cstdlib>
#include <iostream>
#include <istream>
#include <iterator>
#include <map>
#include <ostream>
#include < set>
#include <sstream>
#include <stdexcept>
#include < string>
#include <vector>

#include  " topological_sort.hpp "

typedef std:: string artifact;  /// < A target, dependency, or both

class dependency_graph
{
public:
  typedef std::map<artifact, std:: set<artifact> > graph_type;

   void store_dependency(artifact target, artifact dependency)
  {
    graph_[dependency].insert(target);
  }

  graph_type  const& graph()  const {  return graph_; }

  template< class OutIter>
   void sort(OutIter sorted)
   const
  {
    topological_sort(graph_, sorted);
  }

private:
  graph_type graph_;
};

int main()
{
  dependency_graph graph;

  std:: string line;
   while (std::getline(std::cin, line))
  {
    std:: string target, dependency;
    std::istringstream stream(line);
     if (stream >> target >> dependency)
      graph.store_dependency(target, dependency);
     else  if (not target.empty())
       //  Input line has a target with no dependency,
      
//  so report an error.
      std::cerr <<  " malformed input: target,  " << target <<
                    " , must be followed by a dependency name\n ";
     //  else ignore blank lines
  }

   try {
     //  Get the artifacts in reverse order.
    std::vector<artifact> sorted;
    graph.sort(std::back_inserter(sorted));
     //  Then print them in the correct order.
    std::copy(sorted.rbegin(), sorted.rend(),
              std::ostream_iterator<artifact>(std::cout,  " \n "));
  }  catch (std::runtime_error  const& ex) {
    std::cerr << ex.what() <<  ' \n ';
     return EXIT_FAILURE;
  }
}

ARTIFACT_HPP:

View Code
/* * @file list5603.cpp  */
/* * Listing 56-3. New Definition of an Artifact  */
#ifndef ARTIFACT_HPP_
#define ARTIFACT_HPP_

#include <ctime>
#include < string>

class artifact
{
public:
  artifact() : name_(), mod_time_(static_cast<time_t>(- 1)) {}
  artifact(std:: string  const& name)
  : name_(name), mod_time_(get_mod_time())
  {}

  std:: string  const& name()      const {  return name_; }
  std::time_t        mod_time()  const {  return mod_time_; }

   ///  Build a target.
  
///  After completing the actions (not yet implemented),
  
///  update the modification time.
   void build();

   ///  Look up the modification time of the artifact.
  
///  Return static_cast <time_t> (-1) if the artifact does not
  
///  exist (and therefore must be built) or if the time cannot
  
///  be obtained for any other reason.
  
///  Also see boost::file_system::last_write_time.
  std::time_t get_mod_time()
  {
     //  Real programs should get this information from the
    
//  operating system. This program returns the current time.
     return std::time( 0);
  }
private:
  std:: string name_;
  std::time_t mod_time_;
};

#endif  //  ARTIFACT_HPP_

 

 MAIN2.cpp:

View Code
/* * @file list5604.cpp  */
/* * Listing 56-4. Second Draft, Adding Modification Times to Artifacts  */
#include <algorithm>
#include <cstdlib>
#include <iostream>
#include <istream>
#include <iterator>
#include <map>
#include <ostream>
#include < set>
#include <sstream>
#include <stdexcept>
#include < string>
#include <vector>

#include  " artifact.hpp "
#include  " topological_sort.hpp "

typedef std::size_t artifact_index;

class dependency_graph
{
public:
  typedef std::map<artifact_index, std:: set<artifact_index> > graph_type;

   void store_dependency(artifact_index target, artifact_index dependency)
  {
    graph_[dependency].insert(target);
  }

  graph_type  const& graph()  const {  return graph_; }

  template< class OutIter>
   void sort(OutIter sorted)
   const
  {
    topological_sort(graph_, sorted);
  }

private:
  graph_type graph_;
};

std::vector<artifact> artifacts;
artifact_index lookup_artifact(std:: string  const& name)
{
   for (artifact_index i( 0); i != artifacts.size(); ++i)
     if (artifacts[i].name() == name)
       return i;
   //  Artifact not found, so add it to the end.
  artifacts.push_back(artifact(name));
   return artifacts.size() -  1;
}

int main()
{
  dependency_graph graph;

  std:: string line;
   while (std::getline(std::cin, line))
  {
    std:: string target_name, dependency_name;
    std::istringstream stream(line);
     if (stream >> target_name >> dependency_name)
    {
      artifact_index target(lookup_artifact(target_name));
      artifact_index dependency(lookup_artifact(dependency_name));
      graph.store_dependency(target, dependency);
    }
     else  if (not target_name.empty())
       //  Input line has a target with no dependency,
      
//  so report an error.
      std::cerr <<  " malformed input: target,  " << target_name <<
                    " , must be followed by a dependency name\n ";
     //  else ignore blank lines
  }

   try {
     //  Get the sorted artifact indices in reverse order.
    std::vector<artifact_index> sorted;
    graph.sort(std::back_inserter(sorted));
     //  Then print the artifacts in the correct order.
     for (std::vector<artifact_index>::reverse_iterator it(sorted.rbegin());
         it != sorted.rend();
         ++it)
    {
      std::cout << artifacts.at(*it).name() <<  ' \n ';
    }
  }  catch (std::runtime_error  const& ex) {
    std::cerr << ex.what() <<  ' \n ';
     return EXIT_FAILURE;
  }
}

 MAIN3.cpp:

View Code
/* * @file list5605.cpp  */
/* * Listing 56-5. Storing Pointers in the Dependency Graph  */
#include <algorithm>
#include <cstdlib>
#include <iostream>
#include <istream>
#include <iterator>
#include <map>
#include <ostream>
#include < set>
#include <sstream>
#include <stdexcept>
#include < string>
#include <vector>

#include  " artifact.hpp "
#include  " topological_sort.hpp "

class dependency_graph
{
public:
  typedef std::map<artifact*, std:: set<artifact*> > graph_type;

   void store_dependency(artifact* target, artifact* dependency)
  {
    graph_[dependency].insert(target);
  }

  graph_type  const& graph()  const {  return graph_; }

  template< class OutIter>
   void sort(OutIter sorted)
   const
  {
    topological_sort(graph_, sorted);
  }

private:
  graph_type graph_;
};

std::map<std:: string, artifact> artifacts;

artifact* lookup_artifact(std:: string  const& name)
{
   return &artifacts[name];
}

int main()
{
  dependency_graph graph;

  std:: string line;
   while (std::getline(std::cin, line))
  {
    std:: string target_name, dependency_name;
    std::istringstream stream(line);
     if (stream >> target_name >> dependency_name)
    {
      artifact* target(lookup_artifact(target_name));
      artifact* dependency(lookup_artifact(dependency_name));
      graph.store_dependency(target, dependency);
    }
     else  if (not target_name.empty())
       //  Input line has a target with no dependency, so report an error.
      std::cerr <<  " malformed input: target,  " << target_name <<
                    " , must be followed by a dependency name\n ";
     //  else ignore blank lines
  }

   try {
     //  Get the sorted artifacts in reverse order.
    std::vector<artifact*> sorted;
    graph.sort(std::back_inserter(sorted));
     //  Then print the artifacts in the correct order.
     for (std::vector<artifact*>::reverse_iterator it(sorted.rbegin());
         it != sorted.rend();
         ++it)
    {
      std::cout << (*it)->name() <<  ' \n ';
    }
  }  catch (std::runtime_error  const& ex) {
    std::cerr << ex.what() <<  ' \n ';
     return EXIT_FAILURE;
  }
}

2. 地址与引用

第60讲 智能指针

1. auto_ptr

简单示例:

View Code
/* * @file list6002.cpp  */
/* * Listing 60-2. The Correct Way to Copy auto_ptr Objects  */
#include <memory>

std::auto_ptr< int> does_this_work(std::auto_ptr< int> x)
{
  std::auto_ptr< int> y(x);
   return y;
}

int main()
{
  std::auto_ptr< int> a, b;
  a.reset( new  int( 42));
  b = does_this_work(a);
}

 

2. shared_ptr

简单示例:

View Code
/* * @file list6003.cpp  */
/* * Listing 60-3. Working with shared_ptr  */
#include <iostream>
#include <memory>
#include <ostream>
#include <vector>

class see_me
{
public:
  see_me( int x) : x_(x) { std::cout <<   " see_me( " << x_ <<  " )\n "; }
  ~see_me()             { std::cout <<  " ~see_me( " << x_ <<  " )\n "; }
   int value()  const     {  return x_; }
private:
   int x_;
};

std::tr1::shared_ptr<see_me> does_this_work(std::tr1::shared_ptr<see_me> x)
{
  std::tr1::shared_ptr<see_me> y(x);
   return y;
}

int main()
{
  std::tr1::shared_ptr<see_me> a, b;
  a.reset( new see_me( 42));
  b = does_this_work(a);
  std::vector<std::tr1::shared_ptr<see_me> > v;
  v.push_back(a);
  v.push_back(b);
}

 

第62讲 枚举

1. C++中的static用法

第64讲 特征萃取与策略

1.特征萃取

2.基于策略的编程

newstring:

View Code
/* * @file list6405.cpp  */
/* * Listing 64-5. The newstring Class Template  */
template< class Char,  class Storage,  class Traits>
class newstring {
public:
   typedef Char value_type;
   typedef std::size_t size_type;
   typedef typename Storage::iterator iterator;
   typedef typename Storage::const_iterator const_iterator;
   newstring() : storage_() {}
   newstring(Storage  const& storage) : storage_(storage) {}
   newstring(newstring  const& str) : storage_(str.storage_) {}
   newstring(Char  const* ptr, size_type size) : storage_() {
      resize(size);
      std::copy(ptr, ptr + size, begin());
   }
 
    static  const size_type npos = static_cast<size_type>(- 1);

   newstring&  operator=(newstring str) { swap(str);  return * this; }
   newstring&  operator=(std:: string  const& str) {
       return * this = newstring(str.data(), str.size());
   }
    void swap(newstring& str) { storage_.swap(str.storage_); }

   Char  operator[](size_type i)  const {  return *(storage_.begin() + i); }
   Char&  operator[](size_type i)      {  return *(storage_.begin() + i); }

    void resize(size_type size, Char value = Char()) {
     storage_.resize(size, value);
   }
    void reserve(size_type size) { storage_.reserve(size); }
   size_type size()  const       {  return storage_.end() - storage_.begin(); }
   size_type max_size()  const   {  return storage_.max_size(); }

   Char  const* c_str()  const {  return storage_.c_str(); }
   Char  const* data()  const  {  return storage_.c_str(); }

   iterator begin()             {  return storage_.begin(); }
   const_iterator begin()  const {  return storage_.begin(); }
   iterator end()               {  return storage_.end(); }
   const_iterator end()  const   {  return storage_.end(); }

   size_type find(newstring  const& s, size_type pos =  0const {
      pos = std::min(pos, size());
      const_iterator result( std::search(begin() + pos, end(),
                             s.begin(), s.end(), Traits::eq) );
       if (result == end())
          return npos;
       else
          return result - begin();
   }
         
private:
   Storage storage_;
};

template< class Traits>
class newstringcmp
{
public:
    bool  operator()(typename Traits::value_type a, typename Traits::value_type b)
    const
   {
       return Traits::cmp(a, b) <  0;
   }
};

template< class Char,  class Storage1,  class Storage2,  class Traits>
bool  operator <(newstring<Char, Storage1, Traits>  const& a,
                newstring<Char, Storage2, Traits>  const& b)
{
    return std::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end(),
                                       newstringcmp<Traits>());
}

template< class Char,  class Storage1,  class Storage2,  class Traits>
bool  operator ==(newstring<Char, Storage1, Traits>  const& a,
                 newstring<Char, Storage2, Traits>  const& b)
{
    return std::equal(a.begin(), a.end(), b.begin(), b.end(), Traits::eq);
}

 

vector_storage:

View Code
/* * @file list6406.cpp  */
/* * Listing 64-6. The vector_storage Class Template  */
#include <vector>

template< class Char>
class vector_storage {
public:
   typedef std::size_t size_type;
   typedef Char value_type;
   typedef typename std::vector<Char>::iterator iterator;
   typedef typename std::vector<Char>::const_iterator const_iterator;

   vector_storage() : string_( 1, Char()) {}

    void swap(vector_storage& storage) { string_.swap(storage.string_); }
   size_type max_size()  const {  return string_.max_size() -  1; }
    void reserve(size_type size) { string_.reserve(size +  1); }
    void resize(size_type newsize, value_type value) {
       //  if the string grows, overwrite the null character, then resize
       if (newsize >= string_.size()) {
         string_[string_.size() -  1] = value;
         string_.resize(newsize +  1, value);
      }
      string_[string_.size() -  1] = Char();
   }
   Char  const* c_str()  const {  return &string_[ 0]; }

   iterator begin()             {  return string_.begin(); }
   const_iterator begin()  const {  return string_.begin(); }
    //  Skip over the trailing null character at the end of the vector
   iterator end()               {  return string_.end() -  1; }
   const_iterator end()  const   {  return string_.end() -  1; }

private:
   std::vector<Char> string_;
};

 

deque_storage:

View Code
/* * @file list6407.cpp  */
/* * Listing 64-7. The deque_storage Class Template  */
template< class Char>
class deque_storage {
public:
   typedef std::size_t size_type;
   typedef Char value_type;
   typedef typename std::deque<Char>::iterator iterator;
   typedef typename std::deque<Char>::const_iterator const_iterator;

   deque_storage() : string_() {}

    void swap(deque_storage& storage) { string_.swap(storage.string_); }
   size_type max_size()  const        {  return string_.max_size(); }
    void reserve(size_type size)      { string_.reserve(size); }
    void resize(size_type size, value_type value) { string_.resize(size, value); }
   Char  const* c_str()  const {
      data_.assign(begin(), end()); 
      data_.push_back(Char());
       return &data_[ 0];
   }

   iterator begin()             {  return string_.begin(); }
   const_iterator begin()  const {  return string_.begin(); }
   iterator end()               {  return string_.end(); }
   const_iterator end()  const   {  return string_.end(); }

private:
   std::deque<Char> string_;
   std::vector<Char> data_;
};

array_storage:

View Code
/* * @file list6408.cpp  */
/* * Listing 64-8. The array_storage Class Template  */
#include <algorithm>
#include <cstdlib>
#include <stdexcept>

template< class Char, std::size_t MaxSize>
class array_storage {
public:
   typedef Char array_type[MaxSize];
   typedef std::size_t size_type;
   typedef Char value_type;
   typedef Char* iterator;
   typedef Char  const* const_iterator;

   array_storage() : size_( 0), string_() { string_[ 0] = Char(); }

    void swap(array_storage& storage) {
       //  linear complexity
      std::swap_ranges(string_.begin(), string_.end(), storage.string_.begin());
      std::swap(size_, storage.size_);
   }
   size_type max_size()  const {  return MaxSize -  1; }
    void reserve(size_type size) {
      if (size > max_size())  throw std::length_error( " reserve ");
   }
    void resize(size_type newsize, value_type value) {
       if (newsize > max_size())
          throw std::length_error( " resize ");
       if (newsize > size_)
         std::fill(begin() + size_, begin() + newsize, value);
      size_ = newsize;
      string_[size_] = Char();
   }
   Char  const* c_str()  const {  return &string_[ 0]; }

   iterator begin()             {  return &string_[ 0]; }
   const_iterator begin()  const {  return &string_[ 0]; }
   iterator end()               {  return begin() + size_; }
   const_iterator end()  const   {  return begin() + size_; }

private:
   size_type size_;
   array_type string_;
};

array_storage2:

View Code
/* * @file list6409.cpp  */
/* * Listing 64-9. The array_storage Class Template, Based on array<>   */
#include <algorithm>
#include <cstdlib>
#include <stdexcept>
#include <array>

template< class Char, std::size_t MaxSize>
class array_storage {
public:
   typedef std::tr1::array<Char, MaxSize> array_type;
   typedef std::size_t size_type;
   typedef Char value_type;
   typedef typename array_type::iterator iterator;
   typedef typename array_type::const_iterator const_iterator;

   array_storage() : size_( 0), string_() { string_[ 0] = Char(); }

    void swap(array_storage& storage) {
      string_.swap(storage.string_);
      std::swap(size_, storage.size_);
   }
   size_type max_size()  const {  return string_.max_size() -  1; }
    void reserve(size_type size) {
      if (size > max_size())  throw std::length_error( " reserve ");
   }
    void resize(size_type newsize, value_type value) {
       if (newsize > max_size())
          throw std::length_error( " resize ");
       if (newsize > size_)
         std::fill(begin() + size_, begin() + newsize, value);
      size_ = newsize;
      string_[size_] = Char();
   }
   Char  const* c_str()  const {  return &string_[ 0]; }

   iterator begin()             {  return string_.begin(); }
   const_iterator begin()  const {  return string_.begin(); }
   iterator end()               {  return begin() + size_; }
   const_iterator end()  const   {  return begin() + size_; }

private:
   size_type size_;
   array_type string_;
};

 

第67讲 元编程

元编程是编写编译时运行的代码

示例代码:

View Code
/* * @file list6702.cpp  */
/* * Listing 67-2. Simple Implementation of the power10 Class Template  */
template<unsigned N>
struct power10
{
   enum t { value =  10 * power10<N –  1>::value };
};

template<>
struct power10< 0>
{
   enum t { value =  1 };
};

 

第68讲 项目4:计算器

代码如下:

 

 

转载于:https://www.cnblogs.com/xkfz007/archive/2012/07/09/2583289.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值