第1讲 打磨工具
1. C++/CLI与C++是不同的
第2讲 阅读C++代码
1.核心语言与标准库
C++与C以及其他很多语言类似,区分核心语言与标准库。核心语言和标准库都是标准语言的一部分,不包含这二者的工具套件是不完整的。
二者的区别在于核心语言是自包含的。例如,有些类型是语言内建的,编译器对其提供内在的支持,而其他类型是通过内建类型来定义的,他们在标准库中声明,使用时需要通知编译器将其导入。
第3讲 整数表达式
第17讲 字符集
1. 单词计数:将单词限定为字母和类字母的字符
代码如下:
#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:身体质量指数
代码如下:
* @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:: string> const& 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. 程序栈/执行栈/调用栈/堆栈帧
原书给出的代码:
#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 ";
}
为了便于查看,对代码做了简单的修改,结果如上图所示:
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)类定义:
* @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
fixed& operator+=( fixed f);
/// Subtraction assignment operator
fixed& operator-=( fixed f);
/// Multiplication assignment operator
fixed& operator*=( fixed f);
/// Division assignment operator
fixed& operator/=( fixed f);
/// Negate this value.
void negate();
/// Pre-increment
fixed& operator++();
/// Post-increment
fixed operator++( int);
/// Pre-decrement
fixed& operator--();
/// 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)类实现:
#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();
}
fixed& fixed:: operator+=( fixed f)
{
value_ += f.value();
return * this;
}
fixed& fixed:: operator-=( fixed f)
{
value_ -= f.value();
return * this;
}
fixed& fixed:: operator*=( fixed f)
{
value_ = (value_ * f.value()) / places10;
return * this;
}
fixed& fixed:: operator/=( fixed f)
{
value_ = (value_ * places10) / f.value();
return * this;
}
void fixed::negate()
{
value_ = -value_;
}
fixed& fixed:: operator++()
{
value_ += places10;
return * this;
}
fixed fixed:: operator++( int)
{
fixed result(* this);
++* this;
return result;
}
fixed& fixed:: 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)异常定义:
#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)测试代码:
/* * 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( 3, 14162);
test(f3.value() == 31416);
fixed f4( 2, 14159265);
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( 31, 4159));
test( fixed( 31.41595) == fixed( 31, 4160));
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 <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 <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:
* 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= long, int 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< char> const& put(std::use_facet<std::money_put< char> >(std::locale()));
put.put(std::ostreambuf_iterator< char>( out), false, out, ' 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> const& get(
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:
/* * 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
fixed& operator+=( fixed f);
/// Subtraction assignment operator
fixed& operator-=( fixed f);
/// Multiplication assignment operator
fixed& operator*=( fixed f);
/// Division assignment operator
fixed& operator/=( fixed f);
/// Negate this value.
void negate();
/// Pre-increment
fixed& operator++();
/// Post-increment
fixed operator++( int);
/// Pre-decrement
fixed& operator--();
/// 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.0, double(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:
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:
#define GCD_HPP_
/// Compute greatest-common-denominator.
/// @param n
/// @param m
int gcd( int n, int m);
#endif
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:
#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( in, false);
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:
/* * 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( 3, 1416);
TEST(c3.value().value() == 314);
currency2 c4( 6, 275);
TEST(c4.value().value() == 628);
currency2 c5( 5, 279);
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( 0, 50));
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>( 314, 100));
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( 3, 14);
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( 31, 59));
TEST(currency2( 31.595) == currency2( 31, 60));
// Adjust the following test to match your native locale.
currency2 big( 1234567, 89);
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:
#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程序
/* * 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:
/* * 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:
/* * 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:
/* * 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:
/* * 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
简单示例:
/* * 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
简单示例:
/* * 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:
/* * 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 = 0) const {
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:
/* * 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:
/* * 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:
/* * 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:
/* * 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讲 元编程
元编程是编写编译时运行的代码
示例代码:
/* * 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:计算器
代码如下: