ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

《C++ Primer》第16章 16.5节习题答案

2021-11-02 22:33:26  阅读:149  来源: 互联网

标签:std const 16 Sales C++ item return 习题 data


《C++ Primer》第16章 模板与泛型编程

16.5节模板特例化 习题答案

练习16.62:定义你自己版本的hash<Sales_data>,并定义一个Sales_data对象的unordered_multiset。将多条交易记录保存到容器中,并打印其内容。

【出题思路】

本题练习类模板特例化。

【解答】

#ifndef PROGRAM16_62_SALES_DATA_H
#define PROGRAM16_62_SALES_DATA_H


#include <string>
#include <iostream>

// unchanged from chapter 14 except for added friend declaration for hash
class Sales_data {
friend class std::hash<Sales_data>;
friend std::ostream &operator<<
                         (std::ostream&, const Sales_data&);
friend std::istream &operator>>(std::istream&, Sales_data&);
friend bool operator==(const Sales_data &, const Sales_data &);

friend std::ostream &print(std::ostream&, const Sales_data&);
friend std::istream &read(std::istream&, Sales_data&);
public:
    // constructors
    Sales_data() = default;
    Sales_data(const std::string &s): bookNo(s) { }
    Sales_data(const std::string &s, unsigned n, double p):
               bookNo(s), units_sold(n), revenue(p*n) { }
    Sales_data(std::istream &);
    std::string isbn() const { return bookNo; }
    Sales_data& operator+=(const Sales_data&);
private:
    double avg_price() const;
    std::string bookNo;
    unsigned units_sold = 0;
    double revenue = 0.0;
};

namespace std {
template <>              // we're defining a specialization with
struct hash<Sales_data>  // the template parameter of Sales_data
{
    // the type used to hash an unordered container must define these types
    typedef size_t result_type;
    typedef Sales_data argument_type; // by default, this type needs ==

    size_t operator()(const Sales_data& s) const;

    // our class uses synthesized copy control and default constructor
    // other members as before
};
}  // close the std namespace; note: no semicolon after the close curly

// non-member Sales_data operations
inline
bool compareIsbn(const Sales_data &lhs, const Sales_data &rhs)
{ return lhs.isbn() < rhs.isbn(); }

inline
bool operator==(const Sales_data &lhs, const Sales_data &rhs)
{
    return lhs.isbn() == rhs.isbn() &&
           lhs.units_sold == rhs.units_sold &&
           lhs.revenue == rhs.revenue;
}
inline
bool operator!=(const Sales_data &lhs, const Sales_data &rhs)
{
    return !(lhs == rhs);
}

Sales_data add(const Sales_data&, const Sales_data&);
std::ostream &print(std::ostream&, const Sales_data&);
std::istream &read(std::istream&, Sales_data&);
Sales_data operator+(const Sales_data&, const Sales_data&);
std::ostream &operator<<(std::ostream&, const Sales_data&);
std::istream &operator>>(std::istream&, Sales_data&);

#endif // PROGRAM16_62_SALES_DATA_H

#include "program16_62_sales_data.h"

#include <string>
using std::istream;
using std::ostream;

// define the hash interface for Sales_data

namespace std {
size_t
hash<Sales_data>::operator()(const Sales_data& s) const
{
    return hash<string>()(s.bookNo) ^
           hash<unsigned>()(s.units_sold) ^
           hash<double>()(s.revenue);
}
}  // close the std namespace; note: no semicolon after the close curly

// remaining members unchanged from chapter 14
Sales_data::Sales_data(istream &is)
{
    is >> *this; // read a transaction from is into this object
}

double Sales_data::avg_price() const
{
    if (units_sold)
        return revenue/units_sold;
    else
        return 0;
}

// member binary operator: left-hand operand is bound to the implicit this pointer
// assumes that both objects refer to the same book
Sales_data& Sales_data::operator+=(const Sales_data &rhs)
{
    units_sold += rhs.units_sold;
    revenue += rhs.revenue;
    return *this;
}

// assumes that both objects refer to the same book
Sales_data
operator+(const Sales_data &lhs, const Sales_data &rhs)
{
    Sales_data sum = lhs;  // copy data members from lhs into sum
    sum += rhs;            // add rhs into sum
    return sum;
}

istream &operator>>(istream &is, Sales_data &item)
{
    double price;  // no need to initialize; we'll read into price before we use it
    is >> item.bookNo >> item.units_sold >> price;
    if (is)        // check that the inputs succeeded
        item.revenue = item.units_sold * price;
    else
        item = Sales_data(); // input failed: give the object the default state
    return is;
}

ostream &operator<<(ostream &os, const Sales_data &item)
{
    os << item.isbn() << " " << item.units_sold << " "
       << item.revenue << " " << item.avg_price();
    return os;
}

// operators replace these original named functions
istream &read(istream &is, Sales_data &item)
{
    double price = 0;
    is >> item.bookNo >> item.units_sold >> price;
    item.revenue = price * item.units_sold;
    return is;
}
ostream &print(ostream &os, const Sales_data &item)
{
    os << item.isbn() << " " << item.units_sold << " "
       << item.revenue << " " << item.avg_price();
    return os;
}

Sales_data add(const Sales_data &lhs, const Sales_data &rhs)
{
    Sales_data sum = lhs;  // copy data members from lhs into sum
    sum += rhs;            // add rhs into sum
    return sum;
}

#include <cstddef>
using std::size_t;

#include <string>
using std::string;

#include <iostream>
using std::cin;
using std::cout;
using std::endl;

#include <unordered_set>
using std::unordered_multiset;

#include <functional>

#include "program16_62_sales_data.h"
using std::hash;

int main()
{
    //使用hash<Sales_data>和Sales_data的==运算符
    unordered_multiset<Sales_data> SDset;
    Sales_data item;
    while(cin >> item){
        SDset.insert(item);
    }
    cout << "SDset.size = " << SDset.size() << endl;
    for(auto sd: SDset)
        cout << sd << endl;
    return 0;
}

运行结果:

练习16.63:定义一个函数模板,统计一个给定值在一个vector中出现的次数。测试你的函数,分别传递给它一个double的vector,一个int的vector以及一个string的vector。

【出题思路】

本题练习定义模板函数。

【解答】

#include <iostream>
#include <vector>
#include <cstring>

using namespace std;
template <typename T>
int occur(vector<T> &vec, const T &v)
{
    int ret = 0;
    for(auto a:vec)
    {
        if(a == v)
            ret++;
    }
    return ret;
}

template <>
int occur(vector<char *> &vec, char *const &v)
{
    int ret = 0;
    for(auto a:vec)
    {
        if(!strcmp(a, v))
            ret++;
    }
    return ret;
}

int main()
{
    vector<double> vd = {1.1, 3.14, 2.2, 3.14, 3.3, 4.4};
    cout << "occur(vd, 3.14)=" << occur(vd, 3.14) << endl;

    vector<int> vi = {0, 1, 2, 3, 4, 5};
    cout << "occur(vi, 0)=" << occur(vi, 0) << endl;

    vector<string> vs = {"Hello", "World", "!"};
    cout << "occur(vs, string(end))=" << occur(vs, string("end")) << endl;

    vector<char *> vp;
    vp.push_back(new char[6]);
    vp.push_back(new char[6]);
    vp.push_back(new char[2]);
    strcpy(vp[0], "Hello");
    strcpy(vp[1], "World");
    strcpy(vp[2], "!");
    char *w = new char[6];
    strcpy(w, "World");
    cout << "occur(vp, w)=" << occur(vp, w) << endl;
    delete []w;
    delete vp[2];
    delete vp[1];
    delete vp[0];

    return 0;
}

运行结果:

练习16.64:为上一题中的模板编写特例化版本来处理vector<const char*>。编写程序使用这个特例化版本。

【出题思路】

本题练习定义特例化版本。

【解答】

见上一题。注意,当注释掉特例化版本时,最后一个occur调用会匹配通用版本,用==比较char *,从而无法找到相等的C风格字符串。

练习16.65:在16.3节(第617页)中我们定义了两个重载的debug_rep版本,一个接受const char*参数,另一个接受char*参数。将这两个函数重写为特例化版本。

【出题思路】

本题练习定义特例化版本。

【解答】

两个特例化版本如下,完整程序见练习16.48。

template<> std::string debug_rep(char *p)
{ return debug_rep(std::string(p)); }
template <> std::string debug_rep(const char *cp)
{ return debug_rep(std::string(cp)); }

练习16.66:重载debug_rep函数与特例化它相比,有何优点和缺点?

【出题思路】

理解特例化与重载的区别。

【解答】

重载是会影响函数匹配的,也就是说,编译器在函数匹配过程中会将新的重载版本作为候选之一来选择最佳匹配。这就需要小心设计,避免实际匹配不如我们所愿。特例化则不影响函数匹配,它并不是为编译器进行函数匹配提供一个新的选择,而是为模板的一个特殊实例提供不同于原模板的特殊定义,本质上是接管了编译器在完成函数匹配后的部分实例化工作。即,当某个模板是最佳匹配时,且需要实例化为这个特殊实例时,不再从原模板进行实例化,而是直接使用这个特例化版本。因此,特例化更为简单——当某个模板不符合我们的需求时,只需设计满足需求的特例化版本即可。

练习16.67:定义特例化版本会影响debug_rep的函数匹配吗?如果不影响,为什么?

【出题思路】

理解特例化。

【解答】

如上题。

标签:std,const,16,Sales,C++,item,return,习题,data
来源: https://blog.csdn.net/chenyijun/article/details/121091582

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有