需包含
Sales_item.h需包含 需要//Sales_item.h
#ifndef SALESITEM_H
// we're here only if SALESITEM_H has not yet been defined
#define SALESITEM_H
// Definition of Sales_item class and related functions goes here
#include <iostream>
#include <string>
class Sales_item {
// these declarations are explained section 7.2.1, p. 270
// and in chapter 14, pages 557, 558, 561
friend std::istream& operator>>(std::istream&, Sales_item&);
friend std::ostream& operator<<(std::ostream&, const Sales_item&);
friend bool operator<(const Sales_item&, const Sales_item&);
friend bool
operator==(const Sales_item&, const Sales_item&);
public:
// constructors are explained in section 7.1.4, pages 262 - 265
// default constructor needed to initialize members of built-in type
Sales_item(): units_sold(0), revenue(0.0) { }
Sales_item(const std::string &book):
bookNo(book), units_sold(0), revenue(0.0) { }
Sales_item(std::istream &is) { is >> *this; }
public:
// operations on Sales_item objects
// member binary operator: left-hand operand bound to implicit this pointer
Sales_item& operator+=(const Sales_item&);
// operations on Sales_item objects
std::string isbn() const { return bookNo; }
double avg_price() const;
// private members as before
private:
std::string bookNo; // implicitly initialized to the empty string
unsigned units_sold;
double revenue;
};
// used in chapter 10
inline
bool compareIsbn(const Sales_item &lhs, const Sales_item &rhs)
{ return lhs.isbn() == rhs.isbn(); }
// nonmember binary operator: must declare a parameter for each operand
Sales_item operator+(const Sales_item&, const Sales_item&);
inline bool
operator==(const Sales_item &lhs, const Sales_item &rhs)
{
// must be made a friend of Sales_item
return lhs.units_sold == rhs.units_sold &&
lhs.revenue == rhs.revenue &&
lhs.isbn() == rhs.isbn();
}
inline bool
operator!=(const Sales_item &lhs, const Sales_item &rhs)
{
return !(lhs == rhs); // != defined in terms of operator==
}
// assumes that both objects refer to the same ISBN
Sales_item& Sales_item::operator+=(const Sales_item& rhs)
{
units_sold += rhs.units_sold;
revenue += rhs.revenue;
return *this;
}
// assumes that both objects refer to the same ISBN
Sales_item
operator+(const Sales_item& lhs, const Sales_item& rhs)
{
Sales_item ret(lhs); // copy (|lhs|) into a local object that we'll return
ret += rhs; // add in the contents of (|rhs|)
return ret; // return (|ret|) by value
}
std::istream&
operator>>(std::istream& in, Sales_item& s)
{
double price;
in >> s.bookNo >> s.units_sold >> price;
// check that the inputs succeeded
if (in)
s.revenue = s.units_sold * price;
else
s = Sales_item(); // input failed: reset object to default state
return in;
}
std::ostream&
operator<<(std::ostream& out, const Sales_item& s)
{
out << s.isbn() << " " << s.units_sold << " "
<< s.revenue << " " << s.avg_price();
return out;
}
double Sales_item::avg_price() const
{
if (units_sold)
return revenue/units_sold;
else
return 0;
}
#endif
演示某一题直接修改 #define NUM***, 如运行10.12题为#define NUM1012;笔记较为零散,都是自己不熟悉的知识点。
习题答案至于一个.cc 中,
chapter 10
1. 算法永远不会执行容器的操作:算法永远不会改变底层容器的大小,算法可能改变容器中保存的元素的值,也可能在容器内移动元素,
但永远不会添加或删除元素。
string sum = accumulate(v.begin(), v.end(),"");
accumulate()函数:将空串当做一个字符串字面值传递给第三个参数是不可以的,会导致一个编译错误。
2. 向目的位置迭代器写入数据的算法假定目的位置足够大,能容纳要写入的元素。插入迭代器能够保证这一点:
通常,我们通过一个迭代器向容器元素赋值时,值被赋予迭代器指向的元素。而通过一个插入迭代器赋值时,一个与
赋值号右侧值相等的元素被添加到容器中。
unique算法重新输入序列,将相邻的重复项消除,并返回一个指向不重复值范围末尾的迭代器。
3. 如果忽略返回类型,lambda根据函数体中的代码推断出返回类型,如果函数体只是要给return语句,则返回类型从返回的表达式
的类型推断而来,否则返回void。
我们不能拷贝ostream对象,唯一捕获ostream的方法是捕获其引用(或指向os的指针)。
lambda不能包含引用捕获,但此时必须保证在lambda执行时变量是存在的。
4. istream_iterator操作:当创建一个流迭代器时,必须指定迭代器将要读写的对象类型。istream_iterator使用>>来读取流。
因此istream_iterator要读取的类型必须定义了输入运算符。使用默认初始化迭代器,这样就创建了一个可以当作尾后值使用的迭代器。
eof被定义为空的istream_iterator,可以当作尾后迭代器。
使用算法操作流迭代器:
istream_iterator<int>in(cin), eof;
cout << accumulate(in,eof, 0)<<endl; //调用计算出从标准输入读取的值的和
ostream_iterator来输出值的序列:
ostream_iterator<int>out_iter(cout, " ");
for(auto e : vec)
*out_iter++ = e; //赋值语句实际上将元素写到cout,等价于out_iter = e;
运算符*和++实际上对ostream_iterator对象不做任何事情,因此忽略它们对程序没有任何影响,但还是推荐第一种,与其他迭代器保持一致。
5. 向输出迭代器写入数据的算法都假定目标空间足够容纳写入的数据。
对于特定容器如list和forward_list,应该优先使用成员函数版本的算法而不是通用算法。
//Sales_item.h
#ifndef SALESITEM_H
// we're here only if SALESITEM_H has not yet been defined
#define SALESITEM_H
// Definition of Sales_item class and related functions goes here
#include <iostream>
#include <string>
class Sales_item {
// these declarations are explained section 7.2.1, p. 270
// and in chapter 14, pages 557, 558, 561
friend std::istream& operator>>(std::istream&, Sales_item&);
friend std::ostream& operator<<(std::ostream&, const Sales_item&);
friend bool operator<(const Sales_item&, const Sales_item&);
friend bool
operator==(const Sales_item&, const Sales_item&);
public:
// constructors are explained in section 7.1.4, pages 262 - 265
// default constructor needed to initialize members of built-in type
Sales_item(): units_sold(0), revenue(0.0) { }
Sales_item(const std::string &book):
bookNo(book), units_sold(0), revenue(0.0) { }
Sales_item(std::istream &is) { is >> *this; }
public:
// operations on Sales_item objects
// member binary operator: left-hand operand bound to implicit this pointer
Sales_item& operator+=(const Sales_item&);
// operations on Sales_item objects
std::string isbn() const { return bookNo; }
double avg_price() const;
// private members as before
private:
std::string bookNo; // implicitly initialized to the empty string
unsigned units_sold;
double revenue;
};
// used in chapter 10
inline
bool compareIsbn(const Sales_item &lhs, const Sales_item &rhs)
{ return lhs.isbn() == rhs.isbn(); }
// nonmember binary operator: must declare a parameter for each operand
Sales_item operator+(const Sales_item&, const Sales_item&);
inline bool
operator==(const Sales_item &lhs, const Sales_item &rhs)
{
// must be made a friend of Sales_item
return lhs.units_sold == rhs.units_sold &&
lhs.revenue == rhs.revenue &&
lhs.isbn() == rhs.isbn();
}
inline bool
operator!=(const Sales_item &lhs, const Sales_item &rhs)
{
return !(lhs == rhs); // != defined in terms of operator==
}
// assumes that both objects refer to the same ISBN
Sales_item& Sales_item::operator+=(const Sales_item& rhs)
{
units_sold += rhs.units_sold;
revenue += rhs.revenue;
return *this;
}
// assumes that both objects refer to the same ISBN
Sales_item
operator+(const Sales_item& lhs, const Sales_item& rhs)
{
Sales_item ret(lhs); // copy (|lhs|) into a local object that we'll return
ret += rhs; // add in the contents of (|rhs|)
return ret; // return (|ret|) by value
}
std::istream&
operator>>(std::istream& in, Sales_item& s)
{
double price;
in >> s.bookNo >> s.units_sold >> price;
// check that the inputs succeeded
if (in)
s.revenue = s.units_sold * price;
else
s = Sales_item(); // input failed: reset object to default state
return in;
}
std::ostream&
operator<<(std::ostream& out, const Sales_item& s)
{
out << s.isbn() << " " << s.units_sold << " "
<< s.revenue << " " << s.avg_price();
return out;
}
double Sales_item::avg_price() const
{
if (units_sold)
return revenue/units_sold;
else
return 0;
}
#endif
//main.cc
#include <fstream>
#include <iostream>
#include <sstream>
#include <vector>
#include <list>
#include <algorithm>
#include <functional>
#include <iterator>
#include "Sales_item.h"
using namespace std;
using namespace placeholders;
#define NUM1032
/*10.7*/
template <typename T> void print(T const& seq){
for(const auto &i : seq) cout << i <<" ";
cout << endl;
}
/*10.9*/
void elimDups(vector<string> &words){
sort(words.begin(), words.end());
auto end_unique = unique(words.begin(), words.end());//返回指向不重复值范围末尾的迭代器
words.erase(end_unique, words.end());
}
/*10.11*/
bool isShorter(const string &str1, const string &str2){
return str1.size() < str2.size();
}
/*10.12*/
struct Sales_data{
string bookNo;
string units_sold;
string revenue;
string isbn() const{ return bookNo; }
};
bool compareIsbn(const Sales_data& sd1, const Sales_data& sd2){
return sd1.isbn().size() < sd2.isbn().size();
}
/*10.13*/
bool predicate(const string &str){
return str.size() >= 5 ;
}
/*10.16*/
void biggies(vector<string> &words, vector<string>::size_type sz){
elimDups(words);
stable_sort(words.begin(), words.end(),
[](string const& lhs, string const& rhs) {
return lhs.size() < rhs.size();
});
auto wc = find_if(words.begin(), words.end(),
[sz](string const& s) { return s.size() >= sz; });
for_each(wc, words.end(), [](const string& s) { cout << s << " "; });
}
/*10.18*/
void biggies2(vector<string> &words, vector<string>::size_type sz){
elimDups(words);
stable_sort(words.begin(), words.end(),
[](string const& lhs, string const& rhs) {
return lhs.size() < rhs.size();
});
auto wc = partition(words.begin(), words.end(), predicate);
for_each(words.begin(), wc, [](const string& s) { cout << s << " "; });
}
/*10.19*/
void biggies3(vector<string> &words, vector<string>::size_type sz){
elimDups(words);
stable_partition(words.begin(), words.end(),
[sz](string &s) { return s.size() >= sz; });
auto wc = partition(words.begin(), words.end(), predicate);
for_each(words.begin(), wc, [](const string& s) { cout << s << " "; });
}
/*10.20*/
void wordCount(vector<string> &words, vector<string>::size_type sz){
auto wc = count_if(words.begin(), words.end(), [=](const string &s){return s.size()>=6;});
cout << wc;
}
/*10.22*/
bool wordCount2(const string &s, string::size_type sz){
return s.size() > sz;
}
/*10.24*/
bool check_size(const string &s, string::size_type sz){
return s.size() < sz;
}
vector<int>::const_iterator find_first_bigger(const vector<int>& vec, const string& s){
return find_if(vec.cbegin(), vec.cend(), bind(check_size, s, _1));
}
/*10.25*/
bool check_size2(const string &s, string::size_type sz){
return s.size() >= sz;
}
void biggies4(vector<string>& words, vector<string>::size_type sz)
{
elimDups(words);
auto iter = std::stable_partition(words.begin(), words.end(),
bind(check_size2, _1, sz));
for_each(words.begin(), iter,
[](const string& s) { std::cout << s << " "; });
}
/*10.42*/
void elimDups2(list<string> &words){
words.sort();
words.unique();
}
int main(int argc, char** argv){
/*10.1*/
#ifdef NUM101
vector<int> vec;
int val;
while(cin >> val)
vec.push_back(val);
cout << count(vec.begin(), vec.end(), 2) <<endl;
#endif
/*10.2*/
#ifdef NUM102
vector<string> vec;
string str;
while(cin >> str)
vec.push_back(str);
cout << count(vec.cbegin(), vec.cend(), "c++") <<endl;
#endif
/*10.3*/
#ifdef NUM103
vector<int> vec = {1,2,3,4,5};
int sum = accumulate(vec.begin(), vec.end(), 0);
cout << "Sum of vec: "<< sum <<endl;
#endif
/*10.4*/
#ifdef NUM104
vector<double> vec = {1.1, 2.1, 3.1,4.1};
cout << "sum of vector<double>: " <<accumulate(vec.begin(), vec.end(), 0) <<endl;
cout << "最后输入的是个整数,累加的结果被转换成整型"<<endl;
#endif
/*10.5*/
#ifdef NUM105
char c1[10] = "abc";
char c2[10] = "abc";
vector<char*> roster1{c1};
list<char*> roster2{c2};
cout << boolalpha <<equal(roster1.cbegin(), roster1.cend(), roster2.begin()) <<endl;
cout << "char* 得出即使是相同的字符串equal也不相等."<<endl;
#endif
/*10.6*/
#ifdef NUM106
vector<int> vec = {1,2,3,4,5,6,7,8,9};
fill_n(vec.begin(), vec.size(), 0);
for(auto i : vec)
cout<< i <<" "; cout << endl;
#endif
/*10.7*/
#ifdef NUM107
//a
vector<int> vec;
list<int> lst;
int i;
while (cin >> i) lst.push_back(i);
vec.resize(lst.size()); //加入这一句,否则报错,lst为空链表
copy(lst.cbegin(), lst.cend(), vec.begin());
//b
vector<int> v;
v.reserve(10);
fill_n(v.begin(), 10, 0); //没有错误,但是什么也不输出
print(v);
print(vec);
#endif
/*10.8*/
#ifdef NUM108
cout<< "back_iterator是一个插入迭代器,它产生迭代器来用容器操作向容器添加元素,算法并没有改变它的大小,它是通过容器操作改变的. "<<endl;
#endif
/*10.9*/
#ifdef NUM109
vector<string> vec = {"the", "quick", "red","fox", "jumps", "over", "the", "slow", "red", "turtle"};
print(vec);
elimDups(vec);
print(vec);
#endif
/*10.10*/
#ifdef NUM1010
cout <<"因为算法的操作对象是迭代器而非容器本身,所以算法并不会改变容器大小和删减元素. "<<endl;
#endif
/*10.11*/
#ifdef NUM1011
vector<string> vec = {"the", "quick", "red","fox", "jumps", "over", "the", "slow", "red", "turtle"};
print(vec);
elimDups(vec);
stable_sort(vec.begin(), vec.end(), isShorter);
print(vec);
#endif
/*10.12*/
#ifdef NUM1012
string line;
vector<Sales_data> books;
string filename = "./book_sales";
ifstream inf(filename.c_str());
istringstream record;
if(inf){
while(getline(inf, line)){
Sales_data bill;
record.clear();
record.str(line);
record >> bill.bookNo;
record >> bill.units_sold;
record >> bill.revenue;
books.push_back(bill);
}
for(vector<Sales_data>::iterator it = books.begin(); it != books.end(); ++it){
cout << it->bookNo << " " << it-> units_sold <<" "<< it ->revenue;
cout << endl;
}
}else{
cerr << "error: can not open the file: " << filename <<endl;
}
stable_sort(books.begin(), books.end(), compareIsbn);
cout<< "********************" <<" After sort:"<<endl;
for(auto &i : books)
cout << i.bookNo << " " << i.units_sold <<" "<< i.revenue <<endl;
#endif
/*10.13*/
#ifdef NUM1013
vector<string> vec{"a", "as", "aasss", "aaaaassaa", "aaaaaabba", "aaa"};
print(vec);
auto iter = partition(vec.begin(), vec.end(), predicate);
for(auto i = vec.begin(); i != iter; ++i) cout<< *i << " ";
cout <<endl;
#endif
/*10.14*/
#ifdef NUM1014
int add = [](int val1, int val2) { return val1 + val2; }
#endif
/*10.15*/
#ifdef NUM1015
int val1 = 42;
int add = [val1](int val2) {return val1 + val2; }
#endif
/*10.16*/
#ifdef NUM1016
vector<string> vec{"1234", "1234", "1234", "c++", "linux", "linux", "c"};
print(vec);
biggies(vec, 3);
cout << endl;
#endif
/*10.17*/
#ifdef NUM1017
vector<string> vec = {"the", "quick", "red","fox", "jumps", "over", "the", "slow", "red", "turtle"};
print(vec);
sort(vec.begin(), vec.end(),
[](const string &str1, const string &str2){ return str1.size() < str2.size(); });
print(vec);
#endif
/*10.18*/
#ifdef NUM1018
vector<string> vec{"a", "as", "aasss", "aaaaassaa", "aaaaaabba", "aaa"};
print(vec);
cout << "*****"<<endl;
biggies2(vec, 3);
cout << endl;
#endif
/*10.19*/
#ifdef NUM1019
vector<string> vec{"a", "as", "aasss", "aaaaassaa", "aaaaaabba", "aaa"};
print(vec);
cout << "*****"<<endl;
biggies2(vec, 3);
cout << endl;
#endif
/*10.20*/
#ifdef NUM1020
vector<string> vec{"a", "as", "aasss", "aaaaassaa", "aaaaaabba", "aaa"};
print(vec);
wordCount(vec, 6);
cout << " words bigger than 6" <<endl;
#endif
/*10.21*/
#ifdef NUM1021
int val = 5;
auto f = [&val]()mutable { return --val ? false : true; };
while(!f())
cout << val <<" ";
cout << val <<endl;;
#endif
/*10.22*/
#ifdef NUM1022
vector<string> vec{"a", "as", "aasss", "aaaaassaa", "aaaaaabba", "aaa"};
cout << count_if(vec.cbegin(), vec.cend(), bind(wordCount2, _1, 6)) <<" words > 6"<<endl;
#endif
/*10.23*/
#ifdef NUM1023
cout <<"如果函数被绑定了n个参数,那么bind绑定了n-1个参数,还有一个参数是参数本身. "<<endl;
#endif
/*10.24*/
#ifdef NUM1024
vector<int> vec{1,2,3,4,5,6,7,8,9};
string s{"linux"};
cout << *find_first_bigger(vec, s) << endl;
#endif
/*10.25*/
#ifdef NUM1025
vector<string> vec{"a", "as", "aasss", "aaaaassaa", "aaaaaabba", "aaa"};
print(vec);
cout << biggies4(vec, 4) << " words bigger than 4 ."<<endl;
#endif
/*10.26*/
#ifdef NUM1026
cout <<"back_inserter创建一个使用push_back的迭代器."
"front_inserter创建一个使用push_front的迭代器. "
"inserter创建一个使用insert的迭代器,此函数接受第二个参数,这个参数必须是一个指向给定容器的迭代器,元素将被插入到给定迭代器所表示的元素之前. "<<endl;
#endif
/*10.27*/
#ifdef NUM1027
vector<int> vec{1,2,3,4,5,6,7,8,9};
print(vec);
list<int> lst;
unique_copy(vec.begin(), vec.end(), back_inserter(lst));
print(lst);
#endif
/*10.28*/
#ifdef NUM1028
vector<int> vec{1,2,3,4,5,6,7,8,9};
print(vec);
list<int> lst1;
copy(vec.begin(), vec.end(), inserter(lst1, lst1.begin()));
print(lst1);
list<int> lst2;
copy(vec.begin(), vec.end(), back_inserter(lst2));
print(lst2);
list<int> lst3;
copy(vec.begin(), vec.end(), front_inserter(lst3));
print(lst3);
#endif
/*10.29*/
#ifdef NUM1029
ifstream ifn("./book_sales");
istream_iterator<string> in(ifn), eof;
vector<string> vec;
copy(in, eof, back_inserter(vec));
print(vec);
#endif
/*10.30*/
#ifdef NUM1030
istream_iterator<int> in(cin), eof;
vector<int> vec;
while (in != eof) vec.push_back(*in++);
sort(vec.begin(), vec.end());
copy(vec.begin(), vec.end(), ostream_iterator<int>(cout, " "));
cout << endl;
#endif
/*10.31*/
#ifdef NUM1031
istream_iterator<int> in(cin), eof;
vector<int> vec;
while (in != eof) vec.push_back(*in++);
sort(vec.begin(), vec.end());
unique_copy(vec.begin(), vec.end(), ostream_iterator<int>(cout, " "));//打印不重复的数
cout << endl;
#endif
/*10.32*/
#ifdef NUM1032
istream_iterator<Sales_item> in(cin), in_eof;
vector<Sales_item> vec;
while(in != in_eof)
vec.push_back(*in++);
sort(vec.begin(), vec.end(), [](Sales_item const& lhs, Sales_item const& rhs){
return lhs.isbn() < rhs.isbn(); });
for (auto beg = vec.cbegin(), end = beg; beg != vec.cend(); beg = end) {
end = find_if(beg, vec.cend(), [beg](const Sales_item& item) {
return item.isbn() != beg->isbn();
});
cout << accumulate(beg, end, Sales_item(beg->isbn())) << endl;
}
#endif
/*10.33*/
#ifdef NUM1033
ifstream ifn(argv[1]);
ofstream of_odd(argv[2]), of_even(argv[3]);
istream_iterator<int> in(ifn), in_eof;
ostream_iterator<int> out_odd(of_odd, " "), out_even(of_even, "\n");
for_each(in, in_eof, [&out_odd, &out_even](const int i) {
*(i & 0x1 ? out_odd : out_even)++ = i; });
#endif
/*10.34*/
#ifdef NUM1034
vector<int> vec{1,2,3,4,5,6,7,8,9};
print(vec);
copy(vec.rbegin(), vec.rend(), ostream_iterator<int>(cout, " "));
cout << endl;
#endif
/*10.35*/
#ifdef NUM1035
vector<int> vec{1,2,3,4,5,6,7,8,9};
print(vec);
for(auto iter = vec.end()-1; iter >= vec.begin(); --iter)
cout << *iter << " ";
cout << endl;
#endif
/*10.36*/
#ifdef NUM1036
list<int> lst{0,1,2,0,3,0,4,5};
auto zero = find(lst.crbegin(), lst.crend(), 0);
cout <<*++zero << *zero << *zero.base()<<endl;
#endif
/*10.37*/
#ifdef NUM1037
vector<int> vec{1,2,3,4,5,6,7,8,9};
print(vec);
list<int> lst1;
copy(vec.cbegin()+2, vec.cend()-2, back_inserter(lst1));
print(lst1);
#endif
/*10.38*/
#ifdef NUM1038
cout << "输入迭代器: ==, !=, ++, *, -> " << endl;
cout << "输出迭代器 : ++, * "<<endl;
cout << "前向迭代器 : ==, !=, ++, *, -> " <<endl;
cout << "双向迭代器 : ==, !=, ++, --, *, -> "<<endl;
cout << "随机访问迭代器 : ==, !=, <, <=, >, >=, ++, --, +, +=, -, -=, -(two iterators), *, ->, iter[n]== * (iter + n) "<<endl;
#endif
/*10.39*/
#ifdef NUM1039
cout <<"list上的迭代器属于双向迭代器,vector上的属于随机访问迭代器."<<endl;
#endif
/*10.40*/
#ifdef NUM1040
cout << "copy: 第一和第二个要求输入迭代器, 第三个要求输出迭代器."<<endl;
cout << " reverse: 要求双向迭代器" <<endl;
cout << " unique : 前向迭代器." <<endl;
#endif
/*10.41*/
#ifdef NUM1041
cout << "1. 在beg和end范围内用新元素代替老元素."
"2. 如果pred为真,beg到end之间的元素将被新元素代替. "
"3. 在老元素的范围内,拷贝新元素到dest中."
"4. 如果pred为真,在beg到end范围内拷贝新元素到dest. "<<endl;
#endif
/*10.42*/
#ifdef NUM1042
list<string> lst = {"the", "quick", "red","fox", "jumps", "over", "the", "slow", "red", "turtle"};
print(lst);
elimDups2(lst);
print(lst);
#endif
return 0;
}
参考资料:
c++ primer中文版第五版,电子工业出版社。
c++ primer第四版习题解答,人民邮电出版社。
pezy@github https://github.com/pezy/CppPrimer