您的当前位置:首页正文

C++Primer第五版 习题答案(部分) 第十六章模板和泛型编程

2024-11-09 来源:个人技术集锦

16.2

#include<iostream>
template<typename T>

int compare(const T& v1, const T& v2)
{
	if (v1 < v2) return -1;
	if (v2 < v1) return 1;
	return 0;
}
int main()
{
	std::cout << compare(1, 2) << std::endl;	
}

16.4

#include<iostream>
#include<vector>
#include<list>
#include<string>

template<typename Iter,typename T>
Iter find(const Iter beg, const Iter end, const T& val)
{
	for (Iter it = beg; it != end; ++it)
	{
		if (*it == val)
			return it;
	}
}
int main()
{
	std::vector<int>vi = { 1,2,3,4,5 };
	std::list < std::string > ls = { "aaa","bbb","ccc" };
	std::cout << *(::find(vi.begin(), vi.end(), 3)) << std::endl;
	std::cout << *(::find(ls.begin(), ls.end(), "ccc")) << std::endl;
	return 0;
}

16.5

#include<iostream>
#include<string>

template<typename T>
void print(const T& arr)
{
	for (auto elem : arr)
		std::cout << elem << std::endl;	
}

int main()
{
	int a1[] = { 1,5,2,3,6 };
	char b1[] = "hello";
	print(a1);
	print(b1);
	return 0;
}

16.6

#include<iostream>
#include<string>

template<typename T,unsigned N>
T* begin(T(&arr)[N])
{
	return arr;
}
template<typename T, unsigned N>
T* end(T(&arr)[N])
{
	return arr + N;
}

int main()
{
	char a[] = "hello";
	std::cout << *(begin(a)) << std::endl;
	std::cout << *(end(a)-2) << std::endl;
	return 0;
}

16.7

#include<iostream>
#include<string>

template<typename T,unsigned size>
constexpr unsigned getSize(const T(&)[size])
{
	return size;
}
int main()
{
	char a1[] = "hello";
	std::cout << getSize(a1) << std::endl;
	return 0;
}

16.12

#ifndef STRBLOB_H_
#define STRBLOB_H_
#include<iostream>
#include<vector>
#include<memory>
#include<initializer_list>
#include<stdexcept>

template<typename T>
class ConstStrBlobPtr;

template<typename T>
class StrBlob
{
public:
	friend class ConstStrBlobPtr<T>;

	typedef typename std::vector<T>::size_type size_type;
	StrBlob();
	StrBlob(std::initializer_list<T> il);
	size_type size()const { return data->size(); }
	bool empty()const { return data->empty(); }
	void push_back(const T& t) { data->push_back(t); }
	void pop_back();
	T& front();
	T& back();
	const T& front()const;
	const T& back()const;
	ConstStrBlobPtr<T> begin();
	ConstStrBlobPtr<T>end();
private:
	std::shared_ptr<std::vector<T>> data;
	void check(size_type i, const T& msg)const;
};

template <typename T>
class ConstStrBlobPtr
{
public:
	ConstStrBlobPtr<T>() :curr(0) {}
	ConstStrBlobPtr<T>(const StrBlob<T>& a, size_t sz = 0) : wptr(a.data), curr(sz) {}
	T& deref()const;
	ConstStrBlobPtr<T>& incr();

private:
	std::shared_ptr<std::vector<T>> check(std::size_t, const T&)const;
	std::weak_ptr<std::vector<int>> wptr;
	std::size_t curr;
};

template<typename T>
std::shared_ptr<std::vector<T>> ConstStrBlobPtr<T>::check(std::size_t i, const T& msg)const
{
	auto ret = wptr.lock();
	if (!ret)
		throw std::runtime_error("unbound ConstStrBlobPtr<T>");
	if (i > ret.size())
		throw std::out_of_range(msg);
	return ret;
}

template<typename T>
ConstStrBlobPtr <T>& ConstStrBlobPtr<T>::incr()
{
	check(curr, "increment past of ConstStrBlobPtr");
	++curr;
	return *this;
}

template<typename T>
StrBlob<T>::StrBlob() :data(data(std::make_shared<std::vector<int>>)) {}

template<typename T>
StrBlob<T>::StrBlob(std::initializer_list<T>il) : data(std::make_shared<std::vector<T>>(il)) {}

template <typename T>
void StrBlob<T>::check(size_type i, const T& msg)const
{
	if (i >= data->size())
		throw std::out_of_range(msg);
}
template<typename T>
T& StrBlob<T>::front()
{
	check(0, "front on empty StrBlob");
	return data->front();
}

template<typename T>
T& StrBlob<T>::back()
{
	check(0, "back on empty set");
	return data->back();
}

template<typename T>
const T& StrBlob<T>::front() const
{
	check(0, "front on empty StrBlob");
	return data->front();
}

template<typename T>
const T& StrBlob<T>::back() const
{
	check(0, "back on empty set");
	return data->back();
}

template<typename T>
void StrBlob<T>::pop_back()
{
	check(0, "pop_back on empty StrBlob");
	data->pop_back();
}
template<typename T>
ConstStrBlobPtr<T>StrBlob<T>::begin() { return ConstStrBlobPtr<T>*this; }

template<typename T>
ConstStrBlobPtr<T> StrBlob<T>::end()
{
	auto ret = ConstStrBlobPtr<T>(*this, data->size());
	return ret;
}


#endif // !STRBLOB_H_

16.14

Screen.h

#ifndef SCREEN_H_
#define SCREEN_H_

#include<vector>
#include<string>

template<unsigned W,unsigned H>

class Screen
{
public:
	using pos = std::string::size_type;

	Screen() = default;
	Screen(char c) :contents(H*W,c) {}
	Screen& move(pos r, pos c);
	Screen& set(char);
	Screen& set(pos, pos, char);
	const Screen& display(std::ostream& os)const { do_display(os); return *this; }
private:
	pos cusor = 0;
	pos height = H, width = W;
	std::string contents;
	void do_display(std::ostream& os) const { os << contents; }

};

template<unsigned W,unsigned H>
inline Screen<W, H>& Screen<W, H>::move(pos r, pos c)
{
	pos row = r * width;
	cusor = row + c;
	return *this;
}
template<unsigned W, unsigned H>
inline Screen <W, H>& Screen<W, H>::set(char c)
{
	contents[cusor] = c;
	return *this;
}


template<unsigned W,unsigned H>
inline Screen <W, H>& Screen<W, H>::set(pos r, pos col, char c)
{
	contents[r * width + col] = c;
	return *this;
}

#endif // !SCREEN_H

main.cpp

#include<iostream>
#include<string>
#include"Screen.h"


int main()
{
	Screen<5, 5> myScreen('X');
	myScreen.move(4, 0).set('#').display(std::cout);
	std::cout << "\n";
	myScreen.display(std::cout);
	std::cout << "\n";

}

16.15

Screen.h

#ifndef SCREEN_H_
#define SCREEN_H_

#include<vector>
#include<string>

template<unsigned W,unsigned H>

class Screen
{
public:
	using pos = std::string::size_type;

	friend std::ostream& operator<<(std::ostream& os, const Screen <H, W>& c)
	{
		unsigned int i, j;
		for (i = 0; i < c.height; ++i)
		{
			os << c.contents.substr(i * W, W) << std::endl;
		}
		return os;
	}

	friend std::istream& operator>>(std::istream& is, Screen& c)
	{
		char a;
		is >> a;
		std::string tmp(H * W, a);
		c.contents = tmp;
		return is;
	}

	Screen() = default;
	Screen(char c) :contents(H*W,c) {}

	char get()const { return contents[cursor]; }
	char get(pos r, pos c)const { return contents[r * width + c]; }
	Screen& move(pos r, pos c);
	Screen& set(char);
	Screen& set(pos, pos, char);
	Screen& display(std::ostream& os) { do_display(os); return *this; }
	const Screen& display(std::ostream& os)const { do_display(os); return *this; }
private:
	pos cursor = 0;
	pos height = H, width = W;
	std::string contents;
	void do_display(std::ostream& os) const { os << contents; }

};

template<unsigned W,unsigned H>
inline Screen<W, H>& Screen<W, H>::move(pos r, pos c)
{
	pos row = r * width;
	cursor = row + c;
	return *this;
}
template<unsigned W, unsigned H>
inline Screen <W, H>& Screen<W, H>::set(char c)
{
	contents[cursor] = c;
	return *this;
}


template<unsigned W,unsigned H>
inline Screen <W, H>& Screen<W, H>::set(pos r, pos col, char c)
{
	contents[r * width + col] = c;
	return *this;
}

#endif // !SCREEN_H

main.cpp

#include<iostream>
#include<string>
#include"Screen.h"


int main()
{
	Screen<5, 5> myScreen('X');
	myScreen.move(4, 0).set('#').display(std::cout);
	std::cout << "\n";
	myScreen.display(std::cout);
	std::cout << "\n";
	std::cout << myScreen << std::endl;

}

16.16

Vec.h

#ifndef VEC_H_
#define VEC_H_

#include <string>
#include <utility>
#include <memory>
#include <algorithm>

template <typename T>
class Vec;

template <typename T>
bool operator==(Vec<T>& lhs, Vec<T>& rhs);

template <typename T>
bool operator!=(Vec<T>& lhs, Vec<T>& rhs);

template <typename T>
bool operator<(Vec<T>& lhs, Vec<T>& rhs);

template <typename T>
bool operator>(Vec<T>& lhs, Vec<T>& rhs);

template <typename T>
bool operator<=(Vec<T>& lhs, Vec<T>& rhs);

template <typename T>
bool operator>=(Vec<T>& lhs, Vec<T>& rhs);

template <typename T>
class Vec
{
    friend bool operator== <T> (Vec& lhs, Vec& rhs);
    friend bool operator!= <T> (Vec& lhs, Vec& rhs);
    friend bool operator< <T> (Vec& lhs, Vec& rhs);
    friend bool operator> <T> (Vec& lhs, Vec& rhs);
    friend bool operator<= <T> (Vec& lhs, Vec& rhs);
    friend bool operator>= <T> (Vec& lhs, Vec& rhs);

public:
    Vec() : elements(nullptr), first_free(nullptr), cap(nullptr) { }
    Vec(std::initializer_list<T>);
    Vec(const Vec&);
    Vec(Vec&& s) noexcept : alloc(std::move(s.alloc)), elements(std::move(s.elements)), first_free(std::move(s.first_free)), cap(std::move(s.cap)) { s.elements = s.first_free = s.cap = nullptr; }
    Vec& operator=(const Vec&);
    Vec& operator=(Vec&&) noexcept;
    T& operator[](std::size_t n) { return elements[n]; }
    const T& operator[](std::size_t n) const { return elements[n]; }
    ~Vec();
    void push_back(const T&);
    size_t size() const { return first_free - elements; }
    size_t capacity() const { return cap - elements; }
    T* begin() const { return elements; }
    T* end() const { return first_free; }
    void reserve(size_t n);
    void resize(size_t n);
    void resize(size_t n, const T& s);
private:
    std::allocator<T> alloc;
    void chk_n_alloc() { if (size() == capacity()) reallocate(); }
    std::pair<T*, T*> alloc_n_copy(const T*, const T*);
    void free();
    void reallocate();
    T* elements;
    T* first_free;
    T* cap;
};

template <typename T>
Vec<T>::Vec(std::initializer_list<T> il)
{
    auto newdata = alloc_n_copy(il.begin(), il.end());
    elements = newdata.first;
    first_free = cap = newdata.second;
}

template <typename T>
void Vec<T>::push_back(const T& s)
{
    chk_n_alloc();
    alloc.construct(first_free++, s);
}

template <typename T>
std::pair<T*, T*> Vec<T>::alloc_n_copy(const T* b, const T* e)
{
    auto data = alloc.allocate(e - b);
    return { data, uninitialized_copy(b, e, data) };
}

template <typename T>
void Vec<T>::free()
{
    if (elements)
    {
        std::for_each(elements, first_free, [this](T& p) { alloc.destroy(&p); });
        // for(auto p = first_free; p != elements; )
        //  alloc.destroy(--p);
        alloc.deallocate(elements, cap - elements);
    }
}

template <typename T>
Vec<T>::Vec(const Vec<T>& s)
{
    auto newdata = alloc_n_copy(s.begin(), s.end());
    elements = newdata.first;
    first_free = cap = newdata.second;
}

template <typename T>
Vec<T>::~Vec()
{
    free();
}

template <typename T>
void Vec<T>::reserve(size_t n)
{
    if (n > capacity()) return;
    auto newdata = alloc.allocate(n);
    auto dest = newdata;
    auto elem = elements;
    for (size_t i = 0; i != size(); ++i)
        alloc.construct(dest++, std::move(*elem++));
    free();
    elements = newdata;
    first_free = dest;
    cap = elements + n;
}

template <typename T>
void Vec<T>::resize(size_t n)
{
    resize(n, T());
}

template <typename T>
void Vec<T>::resize(size_t n, const T& s)
{
    if (n < size())
    {
        while (n < size())
            alloc.destroy(--first_free);
    }
    else if (n > size())
    {
        while (n > size())
            push_back(s);
        // alloc.construct(first_free, s);
    }
}

template <typename T>
Vec<T>& Vec<T>::operator=(const Vec<T>& rhs)
{
    auto data = alloc_n_copy(rhs.begin(), rhs.end());
    free();
    elements = data.first;
    first_free = cap = data.second;
    return *this;
}

template <typename T>
Vec<T>& Vec<T>::operator=(Vec<T>&& rhs) noexcept
{
    if (this != &rhs)
    {
        free();
        alloc = std::move(rhs.alloc);
        elements = std::move(rhs.elements);
        first_free = std::move(rhs.first_free);
        cap = std::move(rhs.cap);
        rhs.elements = rhs.first_free = rhs.cap = nullptr;
    }
    return *this;
}

template <typename T>
void Vec<T>::reallocate()
{
    auto newcapacity = size() ? 2 * size() : 1;
    auto newdata = alloc.allocate(newcapacity);
    auto dest = newdata;
    auto elem = elements;
    for (size_t i = 0; i != size(); ++i)
        alloc.construct(dest++, std::move(*elem++));
    free();
    elements = newdata;
    first_free = dest;
    cap = elements + newcapacity;
}

template <typename T>
bool operator==(Vec<T>& lhs, Vec<T>& rhs)
{
    return lhs.size() == rhs.size() && std::equal(lhs.begin(), lhs.end(), rhs.begin());
}

template <typename T>
bool operator!=(Vec<T>& lhs, Vec<T>& rhs)
{
    return !(lhs == rhs);
}

template <typename T>
bool operator<(Vec<T>& lhs, Vec<T>& rhs)
{
    return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
}

template <typename T>
bool operator>(Vec<T>& lhs, Vec<T>& rhs)
{
    return rhs < lhs;
}

template <typename T>
bool operator<=(Vec<T>& lhs, Vec<T>& rhs)
{
    return !(rhs < lhs);
}

template <typename T>
bool operator>=(Vec<T>& lhs, Vec<T>& rhs)
{
    return !(lhs < rhs);
}

#endif

main.cpp

#include"Vec.h"
#include<string>
int main()
{

	Vec<std::string> s({ "aaa","bbb" });
	return 0;
}

16.19

#include<iostream>
#include<string>
#include<vector>

template<typename T>
void print_vector(T& v)
{
	for (typename T::size_type i = 0; i != v.size(); ++i)
		std::cout << v[i]<<" ";
	std::cout << std::endl;
}

int main()
{
	std::vector<std::string>vs = {"a","bb","ccc"};
	print_vector(vs);
	std::vector<int>vi = { 1,2,3,4,5 };
	print_vector(vi);
	return 0;
}

16.20

#include<iostream>
#include<string>
#include<vector>

template<typename T>
void print_vector(T& v)
{
	for (typename T::size_type i = 0; i != v.size(); ++i)
		std::cout << v[i]<<" ";
	std::cout << std::endl;
}

template<typename T>
void print_vector2(T& v)
{
	for(typename T::iterator iter=v.begin();iter!=v.end();++iter)
		std::cout << *iter << " ";
	std::cout << std::endl;
}


int main()
{
	std::vector<std::string>vs = {"a","bb","ccc"};
	print_vector(vs);
	print_vector2(vs);

	std::vector<int>vi = { 1,2,3,4,5 };
	print_vector(vi);
	print_vector2(vi);
	return 0;
}

16.21

#include<iostream>

class DebugDelete 
{
public:
	DebugDelete(std::ostream& s = std::cerr) :os(s) {};
	template <typename T> void operator()(T* p)const
	{
		os << "deleting unique_ptr" << std::endl;
		delete p;
	}
		
private:
	std::ostream& os;
};


int main()
{
	int* p = new int;
	DebugDelete d;
	d(p);
	return 0;
}

16.22

#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"
#include "DebugDelete.h"

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>, DebugDelete());
            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);
    else
        return 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

16.23

#ifndef BLOB_H_
#define BLOB_H_
#include<vector>
#include<memory>

template<typename T>
class Blob
{
	template<typename It>
	Blob(It begin, It end);

private:
	std::shared_ptr<std::vector<T>> data;
};

template<typename T>
template<typename It>
Blob<T>::Blob(It begin, It end) :data(std::make_shared<std::vector<T>>(begin,end)) {};

#endif // !BLOB_H_

16.28

shared_pointer.h

#pragma once
#include<functional>
#include"deleter.h"

namespace cp5 
{
template<typename T>
class SharedPointer;

template<typename T>
void swap(SharedPointer<T>& lhs, SharedPointer<T>& rhs)
{
	using std::swap;
	swap(lhs.ptr, rhs.ptr);
	swap(lhs.ref_count, rhs.count);
	swap(lhs.deleter, rhs.deleter);
}

template<typename T>
class SharedPointer
{
public:
	SharedPointer() :ptr(nullptr), ref_count(new std::size_t(1)), deleter{ cp5::Delete{} } {}
	explicit SharedPointer(T* raw_ptr) :ptr(raw_ptr), ref_count(new std::size_t(1)),
		deleter{ cp5::Delete{} } {}
	SharedPointer(SharedPointer const& other) :ptr{ other.ptr }, ref_count{ other.ref_count },
		deleter{ other.deleter } {++* ref_count; }
	SharedPointer(SharedPointer&& other)noexcept :ptr{ other.ptr }, ref_count{ other.ref_count },
		deleter{std::move(other.deleter)} {}
	SharedPointer& operator==(SharedPointer const& rhs)
	{
		++* rhs.ref_count;
		decrement_and_destory();
		ptr = rhs.ptr, ref = rhs.ref_count, deleter = rhs.deleter;
		return *this;
	}

	SharedPointer& operator=(SharedPointer&& rhs)noexcept
	{
		cp5::swap(*this, rhs);
		rhs.decrement_and_destory();
		return *this;
	}

	operator bool()const
	{
		return ptr ? true : false;
	}
	T& operator*()const
	{
		return *ptr;
	}

	T* operator->()const

	{
		return &*ptr;
	}

	std::size_t use_count()const
	{
		return *ref_count;
	}

	T* get()const
	{
		return ptr;
	}

	bool unique()const
	{
		return 1 == *ref_count;
	}
	void swap(SharedPointer& rhs)
	{
		cp5::swap(*this, rhs);
	}

	void reset()
	{
		decrement_and_destory();
	}

	void reset(T* pointer, const std::function<void(T*)>& d)
	{
		reset(pointer);
		deleter = d;
	}

	~SharedPointer()
	{
		decrement_and_destory();
	}
private:
	T* ptr;
	std::size_type* ref_count;
	std::function<void(T*)>deleter;
	void decrement_and_destory()
	{
		if (ptr && 0 == -- * ref_count)
			delete ref_count, deleter(ptr);
		else if (!ptr)
			delete ref_count;
		ref_count = nullptr;
		ptr = nullptr;
	}
};

}

unique_ptr.h

#ifndef UNIQUE_POINTER_H
#define UNIQUE_POINTER_H

template<typename, typename>class unique_pointer;
template<typename T, typename D>void
swap(unique_pointer<T, D>& lhs, unique_pointer<T, D>& rhs);

template<typename T,typename D=DebugDelete>
class unique_pointer
{
	friend void swap(unique_pointer<T, D>& lhs, unique_pointer<T, D>& rhs);
public:
	
	unique_pointer(const unique_pointer&) = delete;
	unique_pointer& operator=(const unique_pointer&) = delete;

	unique_pointer() = default;
	explicit unique_pointer(T* up) :ptr(up) {}

	unique_pointer(unique_pointer&& up)noexcept :ptr(up.ptr) { up.ptr = nullptr; }
	unique_pointer& operator=(unique_pointer&& up)noexcept;
	unique_pointer operator=(std::nullptr_t n)noexcept;

	T& operator*()const { return *ptr; }
	T* operator->()const { return &this->operator*(); }
	operator bool()const { return ptr ? true : false; }
	
	T* get()const noexcept { return ptr; }

	void swap(unique_pointer<T, D>& rhs) { ::swap(*this, rhs); }

	void reset()noexcept { deleter(ptr); ptr = nullptr; }
	void rest(T* p)noexcept { deleter(ptr); ptr = p; }

	T* release();
	~unique_pointer()
	{
		deleter(ptr);
	}
private:
	T* ptr = nullptr;
	D deleter = D();
};

template<typename T,typename D>
inline void swap(unique_pointer<T, D>& lhs, unique_pointer<T, D>& rhs)
{
	using std::swap;
	swap(lhs.ptr, rhs.ptr);
	swap(lhs.deleter, rhs.deleter);
}

template<typename T, typename D>
inline unique_pointer <T, D>& unique_pointer<T, D>::operator=(unique_pointer&& rhs)noexcept
{
	if (this->ptr!rhs.ptr)
	{
		delete(ptr);
		ptr = nullptr;
		::swap(*this, rhs);
	}
	return *this;
}

template<typename T, typename D>
inline unique_pointer<T, D>& unique_pointer<T, D>::operator=(std::nullptr_t n)noexcept
{
	if (n == nullptr)
	{
		delete(ptr);
		ptr = nullptr;
	}
	return *this;
}

template<typename T, typename D>
inline T* unique_pointer<T, D>::release()
{
	T* ret = ptr;
	ptr = nullptr;
	return ret;
}

#endif // !UNIQUE_POINTER_H

16.29

#ifndef BLOB_H_
#define BLOB_H_

#include <vector>
#include <memory>
#include "shared_pointer.h"

template <typename T>
class Blob
{
public:
    // template <typename It>
    // Blob(It begin, It end) : data(std::make_shared<std::vector<T>>(begin, end)) { }
    template <typename It>
    Blob(It begin, It end);
private:
    cp5::shared_pointer<std::vector<T>> data;
};

template <typename T>
template <typename It>
Blob<T>::Blob(It begin, It end) : data(std::make_shared<std::vector<T>>(begin, end)) { }

#endif

16.41

#include <iostream>

template <typename T>
auto sum(T lhs, T rhs) -> decltype(lhs + rhs)
{
    return lhs + rhs;
}

int main()
{
    auto s = sum(123456789123456789123456, 123456789123456789123456);
   
    return 0;
}

16.47

#include<iostream>
#include<memory>

void func_lvalue(std::string& lhs, std::string& rhs)
{
	lhs = "gao\n";
	rhs = "xu\n";
}

void func_rvalue(int&& lhs, int&& rhs)
{
	//allocate enough space
	std::allocator<int> alloc;
	int* data(alloc.allocate(3));

	//move into the space newly allocated
	alloc.construct(data, lhs);
	alloc.construct(data + 1, 0);
	alloc.construct(data + 2, rhs);

	//print
	for (auto p = data; p != data + 3; ++p)
		std::cout << *p << "\n";

	//destory and deallocation
	for (auto p = data + 3; p != data;)
		alloc.destroy(--p);
	alloc.deallocate(data, 3);
}

template<typename F,typename T1,typename T2>
void flip(F f, T1&& t1, T2&& t2)
{
	f(std::forward<T2>(t2), std::forward<T1>(t1));
}

int main()
{
	//test for lvalue reference
	std::string s1, s2;
	flip(func_lvalue, s1, s2);
	std::cout << s1 << s2;

	//test for rvalue reference
	flip(func_rvalue, 99, 88);
	return 0;


}

16.50

#include<iostream>

template <typename T>
void f(T t)
{
	std::cout << "template <typename T> void f(T t)" << std::endl;
}

template <typename T>
void f(const T* t)
{
	std::cout << "template <typename T> void f(const T*t)" << std::endl;
}

template <typename T>
void g(T t)
{
	std::cout << "template <typename T> void g(T t)" << std::endl;
}

template <typename T>
void g(const T* t)
{
	std::cout << "template <typename T> void g(const T*t)" << std::endl;
}

int main()
{
	int i = 42, * p = &i;
	const int ci = 0, * pi = &ci;
	g(42);
	g(p);
	g(ci);
	g(pi);

	f(42);
	f(p);
	f(ci);
	f(pi);
	return 0;
}

16.50

#include <iostream>

template <typename T>
void f(T t)
{
    std::cout << "template <typename T> void f(T t)" << std::endl;
}

template <typename T>
void f(const T* t)
{
    std::cout << "template <typename T> void f(const T *t)" << std::endl;
}

template <typename T>
void g(T t)
{
    std::cout << "template <typename T> void g(T t)" << std::endl;
}

template <typename T>
void g(T* t)
{
    std::cout << "template <typename T> void g(T *t)" << std::endl;
}

int main()
{
    int i = 42, * p = &i;
    const int ci = 0, * p2 = &ci;

    g(42);
    g(p);
    g(ci);
    g(p2);

    f(42);
    f(p);
    f(ci);
    f(p2);

    return 0;
}

16.52

#include<iostream>

template<typename T,typename ...Args>
void Foo(const T& t, const Args&...rest)
{
	std::cout << sizeof...(Args) << std::endl;
	std::cout << sizeof...(rest) << std::endl;
}

int main()
{
	int i = 0;
	double d = 3.14;
	std::string s = "how are you";
	Foo(i, s, 42, d);
	Foo(s, 42, d);
	Foo(d, s);
	Foo("hi");
	return 0;
}

16.53

#include<iostream>
#include<string>

template<typename T>
std::ostream& print(std::ostream& os, const T& t)
{
	os << t;
	return os;
}
template<typename T,typename ...Args>
std::ostream& print(std::ostream& os, const T& t, const Args&...rest)
{
	os << t<<", ";
	return print(os, rest...);
}

int main()
{
	int i=1, * p = &i;
	double d = 0.1;
	std::string s = "aaa";
	print(std::cout, i);
	std::cout << std::endl;

	print(std::cout, i, d);
	std::cout << std::endl;

	print(std::cout, i, d, s, p, "bbb");
	std::cout << std::endl;

	return 0;

}

16.56

#include<iostream>
#include<memory>
#include<sstream>

template <typename T>std::string debug_rep(const T& t);
template <typename T>std::string debug_rep(T* p);
std::string debug_rep(const std::string& s);
std::string debug_rep(char* p);
std::string debug_rep(const char* p);

template <typename T>
std::string debug_rep(const T& t)
{
	std::ostringstream ret;
	ret << t;
	return ret.str();
}

template <typename T>
std::string debug_rep(const T *p)
{
	std::ostringstream ret;
	ret << "pointer:"<<p;
	if (p)
		ret << " " << debug_rep(*p);
	else
		ret << "null pointer";
	return ret.str();
}

std::string debug_rep(const std::string& s)
{
	return '"' + s + '"';
}

std::string debug_rep(char *p)
{
	return debug_rep(std::string(p));
}
std::string debug_rep(const char* p)

{
	std::cout <<"debug_rep(const char* p)" << std::endl;
	return debug_rep(std::string(p));
}

template<typename T>
std::ostream& print(std::ostream& os, const T& t)
{
	os << t << " ,";
	return os;
}

template<typename T,typename ...Args>
std::ostream& print(std::ostream& os, const T& t, const Args&...rest)
{
	os << t << ",";
	return print(os, rest...);
}

template<typename ...Args>
std::ostream& errorMsg(std::ostream& os,  const Args&...rest)
{
	return  print(os, debug_rep(rest)...);
}

int main()
{
	std::string s = "aaa";
	errorMsg(std::cout, 1, 4, "b", s);
	
	return 0;
}

16.58

#ifndef STRVEC_H_
#define STRVEC_H_

#include <string>
#include <utility>
#include <memory>
#include <algorithm>

class StrVec
{
friend bool operator==(StrVec &lhs, StrVec &rhs);
friend bool operator!=(StrVec &lhs, StrVec &rhs);
friend bool operator<(StrVec &lhs, StrVec &rhs);
friend bool operator>(StrVec &lhs, StrVec &rhs);
friend bool operator<=(StrVec &lhs, StrVec &rhs);
friend bool operator>=(StrVec &lhs, StrVec &rhs);
public:
    StrVec() : elements(nullptr), first_free(nullptr), cap(nullptr) { }
    StrVec(std::initializer_list<std::string>);
    StrVec(const StrVec&);
    StrVec(StrVec &&s) noexcept : alloc(std::move(s.alloc)), elements(std::move(s.elements)), first_free(std::move(s.first_free)), cap(std::move(s.cap)) { s.elements = s.first_free = s.cap = nullptr; }
    template <typename... Args>
    void emplace_back(Args&&... args);
    StrVec &operator=(const StrVec&);
    StrVec &operator=(StrVec&&) noexcept;
    std::string& operator[](std::size_t n) { return elements[n]; }
    const std::string& operator[](std::size_t n) const { return elements[n]; }
    ~StrVec();
    void push_back(const std::string&);
    size_t size() const { return first_free - elements; }
    size_t capacity() const { return cap - elements; }
    std::string *begin() const { return elements; }
    std::string *end() const { return first_free; }
    void reserve(size_t n);
    void resize(size_t n);
    void resize(size_t n, const std::string &s);
private:
    std::allocator<std::string> alloc;
    void chk_n_alloc() { if(size() == capacity()) reallocate(); }
    std::pair<std::string*, std::string*> alloc_n_copy(const std::string*, const std::string*);
    void free();
    void reallocate();
    std::string *elements;
    std::string *first_free;
    std::string *cap;
};

StrVec::StrVec(std::initializer_list<std::string> il)
{
    auto newdata = alloc_n_copy(il.begin(), il.end());
    elements = newdata.first;
    first_free = cap = newdata.second;
}

template <typename... Args>
inline void StrVec::emplace_back(Args&&... args)
{
    chk_n_alloc();
    alloc.construct(first_free++, std::forward<Args>(args)...);
}

void StrVec::push_back(const std::string &s)
{
    chk_n_alloc();
    alloc.construct(first_free++, s);
}

std::pair<std::string*,std::string*> StrVec::alloc_n_copy(const std::string *b, const std::string *e)
{
    auto data = alloc.allocate(e-b);
    return {data, uninitialized_copy(b, e, data)};
}

void StrVec::free()
{
    if(elements)
    {
        std::for_each(elements, first_free, [this](std::string &p){ alloc.destroy(&p); });
        // for(auto p = first_free; p != elements; )
        //  alloc.destroy(--p);
        alloc.deallocate(elements, cap-elements);
    }
}

StrVec::StrVec(const StrVec &s)
{
    auto newdata = alloc_n_copy(s.begin(), s.end());
    elements = newdata.first;
    first_free = cap = newdata.second;
}

StrVec::~StrVec()
{
    free();
}

void StrVec::reserve(size_t n)
{
    if(n > capacity()) return;
    auto newdata = alloc.allocate(n);
    auto dest = newdata;
    auto elem = elements;
    for(size_t i = 0; i != size(); ++i)
        alloc.construct(dest++, std::move(*elem++));
    free();
    elements = newdata;
    first_free = dest;
    cap = elements + n;
}

void StrVec::resize(size_t n)
{
    resize(n,std::string());
}

void StrVec::resize(size_t n, const std::string &s)
{
    if(n < size())
    {
        while(n < size())
            alloc.destroy(--first_free);
    }else if(n > size())
    {
        while(n > size())
            push_back(s);
            // alloc.construct(first_free, s);
    }
}

StrVec &StrVec::operator=(const StrVec &rhs)
{
    auto data = alloc_n_copy(rhs.begin(), rhs.end());
    free();
    elements = data.first;
    first_free = cap = data.second;
    return *this;
}

StrVec &StrVec::operator=(StrVec &&rhs) noexcept
{
    if(this != &rhs)
    {
        free();
        alloc = std::move(rhs.alloc);
        elements = std::move(rhs.elements);
        first_free = std::move(rhs.first_free);
        cap = std::move(rhs.cap);
        rhs.elements = rhs.first_free = rhs.cap = nullptr;
    }
    return *this;
}

void StrVec::reallocate()
{
    auto newcapacity = size() ? 2 * size() : 1;
    auto newdata = alloc.allocate(newcapacity);
    auto dest = newdata;
    auto elem = elements;
    for(size_t i = 0; i != size(); ++i)
        alloc.construct(dest++, std::move(*elem++));
    free();
    elements = newdata;
    first_free = dest;
    cap = elements + newcapacity;
}

bool operator==(StrVec &lhs, StrVec &rhs)
{
    return lhs.size() == rhs.size() && std::equal(lhs.begin(), lhs.end(), rhs.begin());
}

bool operator!=(StrVec &lhs, StrVec &rhs)
{
    return !(lhs == rhs);
}

bool operator<(StrVec &lhs, StrVec &rhs)
{
    return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
}

bool operator>(StrVec &lhs, StrVec &rhs)
{
    return rhs < lhs;
}

bool operator<=(StrVec &lhs, StrVec &rhs)
{
    return !(rhs < lhs);
}

bool operator>=(StrVec &lhs, StrVec &rhs)
{
    return !(lhs < rhs);
}

#endif

16.61

#include<iostream>
#include<memory>

namespace ch16 
{

template <typename T,typename ...Args>
std::shared_ptr<T> make_shared(Args&& ...args)
{
	return std::shared_ptr<T>(new T(std::forward<Args>(args)...));
}
}
int main()
{
	auto sp1 = ch16::make_shared<int>(1);
	std::cout << *sp1 << std::endl;

	auto str = ch16::make_shared<std::string>(10, 'c');
	std::cout << *str << std::endl;
	return 0;
}

16.62

Sales_data.h

#ifndef SALES_DATA_H_
#define SALES_DATA_H_

#include <string>

struct Sales_data;

std::istream &operator>>(std::istream &is, Sales_data &item);
std::ostream &operator<<(std::ostream &os, const Sales_data &item);
Sales_data operator+(const Sales_data &lhs, const Sales_data &rhs);

struct Sales_data
{
friend std::istream& operator>>(std::istream&, Sales_data&);
friend std::ostream& operator<<(std::ostream&, const Sales_data&);
friend Sales_data operator+(const Sales_data&, const Sales_data&);
friend bool operator==(const Sales_data&, const Sales_data&);
friend class std::hash<Sales_data>;
public:
    Sales_data(const std::string &s, unsigned n, double p) : bookNo(s), units_sold(n), revenue(p*n){std::cout << "Sales_data(const std::string &s, unsigned n, double p)" << std::endl;}
    Sales_data() : Sales_data("", 0, 0){std::cout << "Sales_data() : Sales_data(\"\", 0, 0)" << std::endl;}
    Sales_data(const std::string &s) : Sales_data(s, 0, 0){std::cout << "Sales_data(const std::string &s) : Sales_data" << std::endl;}
    Sales_data(std::istream &is) : Sales_data(){/*read(is, *this);*/ is >> *this; std::cout << "Sales_data(std::istream &is) : Sales_data()" << std::endl;}
    std::string isbn() const {return bookNo;}
    Sales_data& operator=(const std::string&);
    Sales_data& operator+=(const Sales_data&);
    Sales_data& operator-=(const Sales_data&);
private:
    inline double avg_price() const;

    std::string bookNo;
    unsigned units_sold = 0;
    double revenue = 0.0;
};

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

Sales_data& Sales_data::operator=(const std::string &s)
{
    *this = Sales_data(s);
    return *this;
}

Sales_data& Sales_data::operator+=(const Sales_data &rhs)
{
    units_sold += rhs.units_sold;
    revenue += rhs.revenue;

    return *this;
}

Sales_data& Sales_data::operator-=(const Sales_data &rhs)
{
    units_sold -= rhs.units_sold;
    revenue -= rhs.revenue;

    return *this;
}

std::istream &operator>>(std::istream &is, Sales_data &item)
{
    double price = 0;

    is >> item.bookNo >> item.units_sold >> price;
    if(is)
        item.revenue = price * item.units_sold;
    else
        item = Sales_data();

    return is;
}

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

    return os;
}

Sales_data operator+(const Sales_data &lhs, const Sales_data &rhs)
{
    Sales_data sum = lhs;
    sum += rhs;

    return sum;
}

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;
}

#endif

ex62.cpp

#ifndef SALES_DATA_H_
#define SALES_DATA_H_

#include <string>

struct Sales_data;

std::istream &operator>>(std::istream &is, Sales_data &item);
std::ostream &operator<<(std::ostream &os, const Sales_data &item);
Sales_data operator+(const Sales_data &lhs, const Sales_data &rhs);

struct Sales_data
{
friend std::istream& operator>>(std::istream&, Sales_data&);
friend std::ostream& operator<<(std::ostream&, const Sales_data&);
friend Sales_data operator+(const Sales_data&, const Sales_data&);
friend bool operator==(const Sales_data&, const Sales_data&);
friend class std::hash<Sales_data>;
public:
    Sales_data(const std::string &s, unsigned n, double p) : bookNo(s), units_sold(n), revenue(p*n){std::cout << "Sales_data(const std::string &s, unsigned n, double p)" << std::endl;}
    Sales_data() : Sales_data("", 0, 0){std::cout << "Sales_data() : Sales_data(\"\", 0, 0)" << std::endl;}
    Sales_data(const std::string &s) : Sales_data(s, 0, 0){std::cout << "Sales_data(const std::string &s) : Sales_data" << std::endl;}
    Sales_data(std::istream &is) : Sales_data(){/*read(is, *this);*/ is >> *this; std::cout << "Sales_data(std::istream &is) : Sales_data()" << std::endl;}
    std::string isbn() const {return bookNo;}
    Sales_data& operator=(const std::string&);
    Sales_data& operator+=(const Sales_data&);
    Sales_data& operator-=(const Sales_data&);
private:
    inline double avg_price() const;

    std::string bookNo;
    unsigned units_sold = 0;
    double revenue = 0.0;
};

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

Sales_data& Sales_data::operator=(const std::string &s)
{
    *this = Sales_data(s);
    return *this;
}

Sales_data& Sales_data::operator+=(const Sales_data &rhs)
{
    units_sold += rhs.units_sold;
    revenue += rhs.revenue;

    return *this;
}

Sales_data& Sales_data::operator-=(const Sales_data &rhs)
{
    units_sold -= rhs.units_sold;
    revenue -= rhs.revenue;

    return *this;
}

std::istream &operator>>(std::istream &is, Sales_data &item)
{
    double price = 0;

    is >> item.bookNo >> item.units_sold >> price;
    if(is)
        item.revenue = price * item.units_sold;
    else
        item = Sales_data();

    return is;
}

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

    return os;
}

Sales_data operator+(const Sales_data &lhs, const Sales_data &rhs)
{
    Sales_data sum = lhs;
    sum += rhs;

    return sum;
}

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;
}

#endif

16.64

#include<iostream>
#include<vector>
#include<algorithm>

template<typename T>
size_t get_number(T t, std::vector<T> const& vt)
{
	size_t n = 0;
	auto iter = vt.begin();
	do
	{
		iter = std::find(iter, vt.end(), t);
		if (iter != vt.end())
		{
			++n;
			++iter;
		}

	} while (iter!=vt.end());
	return n;
}

size_t get_number(const char  *p, std::vector<std::string> const& vt)
{
	size_t n = 0;
	auto iter = vt.begin();
	std::string s(p);
	do
	{
		iter = std::find(iter, vt.end(), s);
		if (iter != vt.end())
		{
			++n;
			++iter;
		}

	} while (iter != vt.end());
	return n;
}

template<>
size_t get_number(const char* p, std::vector<const char*> const& vt)
{
	size_t n = 0;
	auto iter = vt.begin();
	std::string s(p);
	do
	{
		iter = std::find(iter, vt.end(), s);
		if (iter != vt.end())
		{
			++n;
			++iter;
		}

	} while (iter != vt.end());
	return n;
}
int main()
{
	std::vector<double> vd = { 1,2,3.14,4,5 };
	std::vector<int> vi = { 1,2,3,4,3,6 };
	std::vector<std::string>vs = { "aaa","bbb","ccc" };
	std::vector<const char*>vcp = { "a","bb","ccc" };

	std::cout << get_number(3.14, vd) << std::endl;
	std::cout << get_number(3, vi) << std::endl;;
	std::cout << get_number("aaa", vs) << std::endl;
	std::cout << get_number("bb", vcp) << std::endl;
	return 0;
}

16.65

#include <iostream>
#include <memory>
#include <sstream>

template <typename T> std::string debug_rep(const T& t);
template <typename T> std::string debug_rep(T* p);
std::string debug_rep(const std::string& s);

template <typename T>
std::string debug_rep(const T& t)
{
    std::ostringstream ret;
    ret << t;
    return ret.str();
}

template <typename T>
std::string debug_rep(T* p)
{
    std::ostringstream ret;
    ret << "pointer: " << p;

    if (p)
        ret << " " << debug_rep(*p);
    else
        ret << " null pointer";
    return ret.str();
}

std::string debug_rep(const std::string& s)
{
    return '"' + s + '"';
}


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

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

int main()
{
    char ca[] = { 'a', 'b', 'c', '\0' };
    std::cout << debug_rep(ca) << std::endl;

    return 0;
}

Top