C++ Primier Plus(第六版) 第十八章 探讨C++新标准编程练习答案

1.下面是一个简短程序的一部分:

int main()
{
	using namespace std;
// list of double deduced from list contents
	auto q = average_list({15.4, 10.7, 9.0});
	cout << q << endl;
// list of int deduced from list contents
	cout << average_list({20, 30, 19, 17, 45, 38}) << endl;
// forced list of double
	auto ad = average_list<double>({'A', 70, 65.33});
	cout << ad << endl;
}

请提供函数average_list(),让该程序变得完整。他应该是一个模板函数,其中的类型参数指定了用作函数参数的initilize_list模板的类型以及函数的返回类型。
本题刚开始笔者想复杂了,计划使用可变参数模板来实现,后面发现实现不了,后面发现本题考查的是initialize_lizer_list类的使用,程序如下:

// pe1.cpp -- use initializer_list
#include <iostream>
#include <initializer_list>

template<typename T>
T average_list(std::initializer_list<T> il);

int main()
{
	using namespace std;
// list of double deduced from list contents
	auto q = average_list({15.4, 10.7, 9.0});
	cout << q << endl;
// list of int deduced from list contents
	cout << average_list({20, 30, 19, 17, 45, 38}) << endl;
// forced list of double
	auto ad = average_list<double>({'A', 70, 65.33});
    cout << ad << endl;
    return 0;
}

template<typename T>
T average_list(std::initializer_list<T> il)
{
    int i = 0;
    T sum = 0;
    for (auto pil = il.begin(); pil != il.end(); pil++, i++)
    {
        sum += *pil;
    }
    return sum / i;
}

运行结果如下:
image

2. 下面是类Cpmv的声明:

class Cpmv
{
public:
    struct Info
    {
        std::string qcode;
        std::string zcode;
    };
private:
    Info *pi;
public:
    Cpmv();
    Cpmv(std::string q, std::string z);
    Cpmv(const Cpmv & cp);
    Cpmv(Cpmv && mv);
    ~Cpmv();
    Cpmv & operator=(const Cpmv & cp);
    Cpmv & operator=(Cpmv && mv);
    Cpmv operator+(const Cpmv & obj) const;
    void Display() const;
};

函数operator+()应创建一个对象,其成员qcode和zcode有操作数的相应成员拼接而成。其提供为移动构造函数和移动赋值运算符实现移动语义的代码。编写一个使用所有这些方法的程序。为方便测试,让各个方法都显示特定的内容,以便直到它们被调用。
本题不算难,考查的是移动复制构造函数和移动赋值函数的定义。调用移动复制函数的过程出现了问题,没有自动完成,因此采用了强制移动。程序如下:

// cpmv.h -- prototype Cpmv class
#ifndef CPMV_H_
#define CPMV_H_
#include <iostream>
#include <string>

class Cpmv
{
public:
    struct Info
    {
        std::string qcode;
        std::string zcode;
    };
private:
    Info *pi;
public:
    Cpmv();
    Cpmv(std::string q, std::string z);
    Cpmv(const Cpmv & cp);
    Cpmv(Cpmv && mv);
    ~Cpmv();
    Cpmv & operator=(const Cpmv & cp);
    Cpmv & operator=(Cpmv && mv);
    Cpmv operator+(const Cpmv & obj) const;
    void Display() const;
};
#endif
// cpmv.cpp -- methods for Cpmv class
#include "cpmv.h"

Cpmv::Cpmv()
{
    std::cout << "Called Cpmv()\n";
    pi = new Info;
}

Cpmv::Cpmv(std::string q, std::string z)
{
    std::cout << "Called Cpmv(string q, string z)\n";
    pi = new Info;
    pi->qcode = q;
    pi->zcode = z;
}

Cpmv::Cpmv(const Cpmv & cp)
{
    std::cout << "Called Cpmv(const Cpmv & cp)\n";
    pi = new Info;
    pi->qcode = cp.pi->qcode;
    pi->zcode = cp.pi->zcode;
}

Cpmv::Cpmv(Cpmv && mv)
{
    std::cout << "Called Cpmv(Cpmv && mv)\n";
    pi = new Info;
    pi = mv.pi;
    mv.pi = nullptr;
}

Cpmv::~Cpmv()
{
    std::cout << "Called ~Cpmv()\n";
    delete pi;
}

Cpmv & Cpmv::operator=(const Cpmv & cp)
{
    std::cout << "Called operator=(const Cpmv & cp)\n";
    if (this == &cp)
        return *this;
    delete pi;
    pi = new Info;
    pi->qcode = cp.pi->qcode;
    pi->zcode = cp.pi->zcode;
    return *this;
}

Cpmv & Cpmv::operator=(Cpmv && mv)
{
    std::cout << "Called operator=(Cpmv && mv)\n";
    if (this == &mv)
        return *this;
    delete pi;
    pi = new Info;
    pi = mv.pi;
    mv.pi = nullptr;
    return *this;
}

Cpmv Cpmv::operator+(const Cpmv & obj) const
{
    std::cout << "Called operator+(const Cpmv & obj) const\n";
    Cpmv temp;
    temp.pi->qcode = pi->qcode + obj.pi->qcode;
    temp.pi->zcode = pi->zcode + obj.pi->zcode;
    return temp;
}

void Cpmv::Display() const
{
    std::cout << "Called Display() const\n";
    std::cout << pi->qcode << '\t';
    std::cout << pi->zcode << '\n';
}
// test_cpmv.cpp -- test the class cpmv
#include "cpmv.h"
#include <utility>

int main()
{
	{
	// using Cpmv(std::string q, std::string z)
		Cpmv one("C++", "Fight!");
		Cpmv two(", I love!",", go go go!");
		one.Display();
		two.Display();
	// using Cpmv(Cpmv && mv) and operator+(const Cpmv & obj)
		std::cout << "\nthree(one + two): ";
		Cpmv three(std::move(one + two));
		three.Display();
	// using Cpmv(const Cpmv & cp)
		Cpmv four(one);
		four.Display();
	// operator=(Cpmv && mv) and operator+(const Cpmv & obj)
		std::cout << "\none = four + two: ";
		one = four + two;
		one.Display();
	// operator=(const Cpmv & mv)
		two = three;
		two.Display();
	}
	std::cout << "Done.\n";
	return 0;
}

运行结果如下:
image

3.编写并测是可变参数模板函数sum_value(),它接受任何长度的参数列表(其中包含数值,但也可以是任何类型),并以long double的方式返回这些数值的和。

本题考查的是可变模板参数:任何类型实际上是有条件的,基本类型,c-字符串类型本程序不支持,支持的类型是定义了+运算符的数据类型,程序如下:

// pe3.cpp -- variadic template
#include <iostream>
#include <iomanip>

template<typename T, typename... Args>
long double sum_value(T value, Args... args);

long double sum_value() { return 0.0; }

int main()
{
    using std::cout;
// list of int and double and char
    auto q = sum_value(1, 2, 9.6, 'a', 10);
    cout << std::fixed << std::setprecision(4);
    cout << q << std::endl;
    auto sum = sum_value('!', 345, 333,'A');
    cout << sum << std::endl;
    return 0;
}

template<typename T, typename... Args>
long double sum_value(T value, Args... args)
{
    return value + sum_value(args...);
}

运行结果如下:
image

4. 使用lambda重新编写程序清单16.15。具体的说,使用一个有名称的lambda函数替换函数outint(),并将函数符替换为两个匿名的lambda表达式。

本题考查的是有名称的lambda函数和匿名lambda表达式的定义,注意有名称的lambda函数使用
auto function-name = [](typename x){...},程序如下:

// pe4.cpp -- use lambda function
#include <iostream>
#include <list>
#include <iterator>
#include <algorithm>

// has name lambda function
auto outint = [](int n) { std::cout << n << " "; };

int main()
{
    using std::list;
    using std::cout;
    using std::endl;

    int vals[10] = {50, 100, 90, 180, 60, 210, 415, 88, 188, 201};
    list<int> yadayada{vals, vals+10};  // range constructor
    list<int> etcetera(vals, vals+10);
// C++11 can use the following instead
    // list<int> yadayada = {50, 100, 90, 180, 60, 210, 415, 88, 188, 201};
    // list<int> etcetera{50, 100, 90, 180, 60, 210, 415, 88, 188, 201};
    cout << "Original list:\n";
    for_each(yadayada.begin(), yadayada.end(), outint);
    cout << endl;
    for_each(etcetera.begin(), etcetera.end(), outint);
    cout << endl;
    yadayada.remove_if([](int x){ return x > 100; });
    etcetera.remove_if([](int x){ return x > 200; });
    cout << "Trimmed list:\n";
    for_each(yadayada.begin(), yadayada.end(), outint);
    cout << endl;
    for_each(etcetera.begin(), etcetera.end(), outint);
    cout << endl;
    return 0;
}

运行结果如下:
image

posted @ 2022-01-17 22:14  Fight!GO  阅读(99)  评论(0编辑  收藏  举报