文章目录
- 练习18.11
- 练习18.12
- 练习18.13
- 练习18.14
- 练习18.15
- 练习18.16
- 练习18.17
- 练习18.18
- 练习18.19
- 练习18.20
练习18.11
为什么 what 函数不应该抛出异常?
what中如果抛出异常,需要try catch捕获,再调用what,一直循环,直达内存耗尽。
练习18.12
将你为之前各章练习编写的程序放置在各自的命名空间中。也就是说,命名空间chapter15包含Query程序的代码,命名空间chapter10包含TextQuery的代码;使用这种结构重新编译Query代码实例。
Query.h
#ifndef QUERY_H_
#define QUERY_H_#include <string>
#include <iostream>
#include "Query_base.h"
#include "WordQuery.h"
#include "TextQuery.h"namespace chapter15
{class Query{friend Query operator~(const Query&);friend Query operator|(const Query&, const Query&);friend Query operator&(const Query&, const Query&);public:Query(const std::string&);chapter10::QueryResult eval(const chapter10::TextQuery &t) const { return q->eval(t); }std::string rep() const { std::cout << "Query::rep()" << std::endl; return q->rep(); }private:Query(std::shared_ptr<Query_base> query) : q(query) { std::cout << "Query(std::shared_ptr<Query_base> query)" << std::endl; }std::shared_ptr<Query_base> q;};std::ostream& operator<<(std::ostream &os, const Query &query){return os << query.rep();}inline Query::Query(const std::string &s) : q(new WordQuery(s)) { std::cout << "Query::Query(const std::string &s)" << std::endl; }
}#endif
TextQuery.h
#ifndef TEXTQUERY_H_
#define TEXTQUERY_H_#include <string>
#include <vector>
#include <map>
#include <fstream>
#include <sstream>
#include <set>
#include <memory>
#include <iostream>
#include <algorithm>
#include <iterator>
#include "StrBlob.h"namespace chapter10
{class QueryResult;class TextQuery{public:using line_no = std::vector<std::string>::size_type;TextQuery(std::ifstream&);QueryResult query(const std::string&) const;private:StrBlob file;std::map<std::string, std::shared_ptr<std::set<line_no>>> word_map;};class QueryResult{friend std::ostream& print(std::ostream&, const QueryResult&);public:QueryResult(std::string s, std::shared_ptr<std::set<TextQuery::line_no>> p, StrBlob f) : sought(s), lines(p), file(f) { }std::set<StrBlob::size_type>::iterator begin() const { return lines->begin(); }std::set<StrBlob::size_type>::iterator end() const { return lines->end(); }// std::shared_ptr<StrBlob> get_file() const { return std::make_shared<StrBlob>(file); }const StrBlob& get_file() const { return file; }private:std::string sought;std::shared_ptr<std::set<TextQuery::line_no>> lines;StrBlob file;};TextQuery::TextQuery(std::ifstream &ifs){std::string text_line;while(std::getline(ifs, text_line)){file.push_back(text_line);int line_number = file.size() - 1;std::istringstream line(text_line);std::string text_word;while(line >> text_word){std::string word;std::copy_if(text_word.begin(), text_word.end(), std::back_inserter(word), isalpha);// std::cout << word << std::endl;auto &wm_lines = word_map[word];if(!wm_lines)wm_lines.reset(new std::set<line_no>);wm_lines->insert(line_number);}}}QueryResult TextQuery::query(const std::string &sought) const{static std::shared_ptr<std::set<TextQuery::line_no>> nodata(new std::set<TextQuery::line_no>);auto loc = word_map.find(sought);if(loc == word_map.end())return QueryResult(sought, nodata, file);elsereturn QueryResult(sought, loc->second, file);}std::ostream &print(std::ostream &os, const QueryResult &qr){os << qr.sought << " occurs " << qr.lines->size() << " " /*<< make_plural(qr.lines->size(), "time", "s")*/ << std::endl;for(auto num : *qr.lines){ConstStrBlobPtr p(qr.file, num);os << "\t(line " << num + 1 << ") " << p.deref() << std::endl;}return os;}
}#endif
练习18.13
什么时候应该使用未命名的命名空间?
在需要在其所在的文件中可见,在其所在的文件外不可见时;
static只能用于变量与函数,不可用于用户自定义的类型。
练习18.14
假设下面的operator*声明的是嵌套的命名空间 mathLib::MatrixLib 的一个成员:
namespace mathLib {namespace MatrixLib {class matrix { /* ... */ };matrix operator* (const matrix &, const matrix &);// ...}
}
请问你应该如何在全局作用域中声明该运算符?
mathLib::MatrixLib::matrix mathLib::MatrixLib::operator*(const matrix&, const matrix&);
练习18.15
说明 using 指示与 using 声明的区别。
using指示引入的名字的作用域远比using声明引入的名字的作用域复杂。它具有将命名空间成员提升到包含命名空间本身和using指示的最近作用域的能力。对于using声明来说,我们指示简单地领名字在局部作用域有效。
using指示是令整个命名空间的所有内容变得有效。通常情况下,命名空间中会含有一些不能出现在局部作用域的定义,因此using指示一般被看作是出现在最近的外层作用域中。
练习18.16
假定在下面的代码中标记为“位置1”的地方是对命名空间 Exercise中所有成员的using声明,请解释代码的含义。如果这些using声明出现在“位置2”又会怎样呢?将using声明变为using指示,重新回答之前的问题。
namespace Exercise {int ivar = 0;double dvar = 0;const int limit = 1000;
}
int ivar = 0;
//位置1
void main() {//位置2double dvar = 3.1416;int iobj = limit + 1;++ivar;++::ivar;
}
namespace Exercise{int ivar = 0;double dvar = 0;const int limit = 1000;
}
int ivar = 0;using Exercise::ivar; //1
using Exercise::dvar;
using Exercise::limit;// using namespace Exercise; //3void mainp(){// using Exercise::ivar; //2// using Exercise::dvar;// using Exercise::limit;// using namespace Exercise; //4double dvar = 3.1416;int iobj = limit + 1;++ivar;++::ivar;
}int main()
{return 0;
}
练习18.17
实际编写代码检验你对上一题的回答是否正确。
练习18.18
已知有下面的 swap 的典型定义,当 mem1 是一个 string 时程序使用 swap 的哪个版本?如果 mem1 是 int 呢?说明在这两种情况下名字查找的过程。
void swap(T v1, T v2)
{using std::swap;swap(v1.mem1, v2.mem1);//交换类型的其他成员
}
前者使用string版本的swap;后者使用实例化为int的swap。
练习18.19
如果对 swap 的调用形如 std::swap(v1.mem1, v2.mem1) 将会发生什么情况?
将只使用标准库的swap,如果v1.mem1和v2.mem1为用户自定义类型,将无法使用用户定义的针对该类型的swap。
练习18.20
在下面的代码中,确定哪个函数与compute调用匹配。列出所有候选函数和可行函数,对于每个可行函数的实参与形参的匹配过程来说,发生了哪种类型转换?
namespace primerLib {void compute();void compute(const void *);
}
using primerLib::compute;
void compute(int);
void compute(double, double = 3.4);
void compute(char*, char* = 0);
void f()
{compute(0);
}
候选函数:全部;
可行函数:
void compute(int)(最佳匹配)
void compute(double, double = 3.4)(int->double)
void compute(char*, char* = 0)(0->nullptr)
void compute(const void *)(0->nullptr)
改变后:
void compute(const void *)为最佳匹配。