zoukankan      html  css  js  c++  java
  • 读书笔记之: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:计算器

    代码如下:

  • 相关阅读:
    软件设计7个原则
    vue.js 样式绑定 font-size 问题
    实例理解scala 隐式转换(隐式值,隐式方法,隐式类)
    著名端口整理(常用服务的默认端总结)
    .NET Core Web API 实现大文件分片上传
    ngnix反向代理tomcat,ssl证书配置及自定义错误页面
    微信登录闪退
    gradle如何配置阿里云的中央仓库
    HashMap底层实现和原理
    关于Java中String类的hashCode方法
  • 原文地址:https://www.cnblogs.com/xkfz007/p/2583289.html
Copyright © 2011-2022 走看看