/***********************************
2017年12月28日13:59:12
Athor:xiyuan255
Course:C++
Contain:pe18-1.cpp
Reference: C++ Primer plus
知识点:初始化列表模板类的应用
1.初始化列表模板类:如果没有强制指定模板参数类型,则可以根据
初始化列表包的元素类型,作为制定的模板参数类型。但要求参数
列表包中的元素类型要一致才可以。
2.初始化列表模板类:如果强制指定了模板参数类型,则会将初始化
列表包中的元素都转换为指定的模板参数类型。
说明:C++ Primer plus第十八章的第一题练习题
【 参考 P838 】
*************************************/
// pe18-1.cpp -- uisng template initializer_list
#include <iostream>
#include <initializer_list>
template <typename T> // C++11可以带类型默认值 typename T = double
T average_list(std::initializer_list<T> il)
{
T sum = 0;
for (auto p = il.begin(); p != il.end(); p++)
sum += (*p);
return (il.size() == 0 ? sum : sum / il.size());
}
int main()
{
using namespace std;
// list of double deduced from list constents
auto q = average_list({15.4, 10.7, 9.0}); // T = double
cout << q << endl;
// list of int deduced from list constents
cout << average_list({20, 30, 19, 17, 45, 38}) << endl; // T = int
// forced list of double
auto ad = average_list<double>({'A', 70, 65.33});
cout << ad << endl;
return 0;
}
/**
输出结果:
11.7
28
66.7767
*/
// cpmv.h -- class Cpmv decalaration
#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 && cp); // 移动赋值运算符操作
Cpmv operator+(const Cpmv & obj) const;
void Display() const;
};
#endif /* __CPMV_H__ */
// cpmv.cpp -- class Cpmv methods definition
#include "cpmv.h"
// Cpmv class methods
Cpmv::Cpmv()
{
pi = nullptr;
std::cout << "default constructor called.\n";
}
Cpmv::Cpmv(std::string q, std::string z)
{
pi = new Info;
pi->qcode = q;
pi->zcode = z;
std::cout << "string, string constructor called.\n";
}
Cpmv::Cpmv(const Cpmv & cp)
{
pi = new Info;
pi->qcode = cp.pi->qcode;
pi->zcode = cp.pi->zcode;
std::cout << "copy constructor called.\n";
}
Cpmv::Cpmv(Cpmv && mv)
{
pi = mv.pi;
mv.pi = nullptr;
std::cout << "move constructor called.\n";
}
Cpmv::~Cpmv()
{
delete pi;
std::cout << "destructor called.\n";
}
Cpmv & Cpmv::operator=(const Cpmv & cp)
{
if (this == &cp)
return *this;
pi = new Info;
pi->qcode = cp.pi->qcode;
pi->zcode = cp.pi->zcode;
std::cout << "copy assignment operator called.\n";
return *this;
}
Cpmv & Cpmv::operator=(Cpmv && cp)
{
if (this == &cp)
return *this;
pi = cp.pi;
cp.pi = nullptr;
std::cout << "move assignment operator called.\n";
return *this;
}
Cpmv Cpmv::operator+(const Cpmv & obj) const
{
Cpmv temp; // 会调用默认构造函数创建一个对象
temp.pi = new Info;
temp.pi->qcode = pi->qcode + obj.pi->qcode;
temp.pi->zcode = pi->zcode + obj.pi->zcode;
std::cout << "add assignment operator called.\n";
return temp; // return 返回的类型不是引用类型,所以因为的右值
// 首选调用移动构造函数将temp对象移动到函数的返回值的内
// 存空间中
}
void Cpmv::Display() const
{
std::cout << "pi->qcode: " << pi->qcode << std::endl;
std::cout << "pi->zcode: " << pi->zcode << std::endl;
}
/***********************************
2017年12月29日09:13:41
Athor:xiyuan255
Course:C++
Contain:pe18-2.cpp
Reference: C++ Primer plus
知识点:
1.一般而言,将左值传递给const左值引用参数时,参数将被初始化为
左值。将右值传递给函数时,const左值引用参数将指向右值的临时
拷贝。
2.一般而言,将左值传递给非const左值引用参数时,参数将被初始化
为左值。但非const左值引用参数不能接受右值实参。
3.总之,非const左值形参与左值实参匹配,非const右值形参与右值实
参匹配;const左值形参可与左值或右值实参匹配,但编译器优先选择
前两种方式(如果可供选择的话)。
说明:C++ Primer plus第十八章的第二题练习题
【 参考 P838 】
*************************************/
// pe18-2.cpp -- using class Cpmv
#include <iostream>
#include "cpmv.h"
int main()
{
/* Cpmv("112233", "445566")调用Cpmv(string q, string z)
* 构造函数创建一个临时对象,它属于一个右值,因在定义时
* 用'=',则首选调用Cpmv(Cpmv && mv)移动构造函数将临时
* 对象赋给cpmv1对象。 */
Cpmv cpmv1 = Cpmv("112233", "445566");
Cpmv cpmv2("1234", "5678");
Cpmv cpmv3 = cpmv1;
Cpmv cpmv4;
cpmv4 = cpmv2;
std::cout << "cpmv1 contents:\n";
cpmv1.Display();
std::cout << "cpmv2 contents:\n";
cpmv2.Display();
std::cout << "cpmv3 contents:\n";
cpmv3.Display();
std::cout << "cpmv4 contents:\n";
cpmv4.Display();
Cpmv cpmv5;
/* cpmv3 + cpmv4首先调用cpmv3.operator+(cpmv4)创建一个临时
* 对象,它是一个右值(return返回temp对象右值),然后调用
* cpmv5.operator=(cpmv3 + cpmv4的返回值)移动赋值运算符。*/
cpmv5 = cpmv3 + cpmv4;
std::cout << "cpmv5 contents:\n";
cpmv5.Display();
return 0;
}
/**
输出结果:
string, string constructor called.
move constructor called.
destructor called.
string, string constructor called.
copy constructor called.
default constructor called.
copy assignment operator called.
cpmv1 contents:
pi->qcode: 112233
pi->zcode: 445566
cpmv2 contents:
pi->qcode: 1234
pi->zcode: 5678
cpmv3 contents:
pi->qcode: 112233
pi->zcode: 445566
cpmv4 contents:
pi->qcode: 1234
pi->zcode: 5678
default constructor called.
default constructor called.
add assignment operator called.
move constructor called.
destructor called.
move assignment operator called.
destructor called.
cpmv5 contents:
pi->qcode: 1122331234
pi->zcode: 4455665678
destructor called.
destructor called.
destructor called.
destructor called.
destructor called.
*/
/***********************************
2017年12月29日09:43:41
Athor:xiyuan255
Course:C++
Contain:pe18-3.cpp
Reference: C++ Primer plus
说明:C++ Primer plus第十八章的第三题练习题
【 参考 P838 】
*************************************/
// pe18-3.cpp -- test sum_value() function
#include <iostream>
long double sum_value() // 该函数不会调用
{
return 0;
}
template <typename T>
long double sum_value(const T & value)
{
return value;
}
// 可变参数模板(variadic template)
template <typename T, typename... Args> // Args is a template parameter pack
long double sum_value(const T & value, const Args&... args) // args is a function parameter pack
{ // T使用的类型和Args要一致,如本例中T是const &类型,Args也是。
// 因为T对应的value值就是每次从参数包args取出一个赋给它的,
// 所以要类型一致,每次取出一个,直到参数包args取出最后一个
// 则调用long double sum_value(const T & value)函数结束递归。
return value + sum_value(args...);
}
int main()
{
long double sum = sum_value(1, 2, 3, 4, 5, 6, 7, 8, 9);
std::cout << "sum = " << sum << std::endl;
return 0;
}
/**
输出结果:
sum = 45
*/
/***********************************
2017年12月29日10:19:01
Athor:xiyuan255
Course:C++
Contain:pe18-4.cpp
Reference: C++ Primer plus
说明:C++ Primer plus第十八章的第四题练习题
【 参考 P838 】
*************************************/
// pe18-4.cpp -- using a lambda handler functor
#include <iostream>
#include <list>
#include <iterator>
#include <algorithm>
template<class T> // functor class defines operator()()
class TooBig
{
private:
T cutoff;
public:
TooBig(const T & t) : cutoff(t) { }
bool operator()(const T & v) { return v > cutoff; }
};
//void outint(int n) { std::cout << n << " "; }
auto outint = [](int n) { std::cout << n << " "; }; // lambda
int main()
{
using std::list;
using std::cout;
using std::endl;
TooBig<int> f100(100); // limit = 100
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 lists:\n";
for_each(yadayada.begin(), yadayada.end(), outint);
cout << endl;
for_each(etcetera.begin(), etcetera.end(), outint);
cout << endl;
/* f100类似函数指针,其实调用的是f100(const T & v)
* 即调用f100.operator(v)运算符操作函数,remove_if
* 函数的作用是,将yadayada对象的每个元素依次取出
* 发送给f100.operator(v),如果该函数返回true则移除
* yadayada对象中的该元素,否则不做处理。 */
yadayada.remove_if([](int n){ return n > 100; }); // use a named function object
etcetera.remove_if([](int n){ return n > 200; }); // constuct a function object
cout << "Trimmed lists:\n";
for_each(yadayada.begin(), yadayada.end(), outint);
cout << endl;
for_each(etcetera.begin(), etcetera.end(), outint);
cout << endl;
return 0;
}
/**
输出结果:
Original lists:
50 100 90 180 60 210 415 88 188 201
50 100 90 180 60 210 415 88 188 201
Trimmed lists:
50 100 90 60 88
50 100 90 180 60 88 188
*/