C++Primer 第十六章 模板与泛型编程 习题答案

16.1

编译器用推断出的模板参数为我们实例化一个特定版本的函数,当编译器实例化一个模板时,它使用实际的模板实参代替对应的模板参数来创建一个新的实例。

16.2

template<typename T>
int compare(const T&v1, const T&v2)
{
	if (v1 < v2)return -1;
	if (v2 < v1)return 1;
	return 0;
}

16.3

error: no match for ‘operator<’

16.4

template <typename I,typename S>
I find(I beg, I end, const S& s)
{
	for (; beg != end; ++beg)
	{
		if (*beg == s)
		{
			return beg;
		}
	}
}

16.5

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

int main()
{
	std::string s[] = { "ssss", "aaa", "ssssss" };
	char c[] = { 'a', 'b', 'c', 'd' };
	int  i[] = { 1 };
	print(i);
	print(c);
	print(s);
	return 0;
}

16.6

#include<string>
#include<iostream>
template <typename A,unsigned N>
A* Begin(A(&a)[N])
{
	return a;
}

template <typename A, unsigned N>
A* End(A(&a)[N])
{
	return a+N;
}
int main()
{
	std::string s[] = { "abc","efd","aaa" };
	std::cout << *Begin(s) << std::endl;
	std::cout << *End(s) << std::endl;
}

16.7

#include<string>
#include<iostream>
template <class A,unsigned N> constexpr
int sizeofArray(A(&a)[N])
{
	return N;
}
int main()
{
	std::string s[] = { "aaa","bbb" };
	std::cout << sizeofArray(s) << std::endl;
}

16.8

更多的类定义了 “!=” 运算符,而不是 “<” 运算符。这么做可以减少与模板类一起使用的类的要求。简而言之,为了使用模板类,类必须满足一些要求,比如实现 “==” 或 “<” 运算符等。而 “!=” 运算符在 C++ 中已经默认定义了,因此如果一个类只需要实现 “!=” 运算符,就可以作为模板类的类型参数。这样,使用该模板类的用户就不需要为了满足要求而在类中额外实现 “<” 运算符。

16.9

一个函数模板是一个公式,可以从中生成不同类型版本的该函数。
一个类模板是用来生成类的蓝图的,编译器不能为类模板推断模板参数类型,为了使用类模板,必须在模板名字的尖括号中提供额外信息。

16.10

使用类模板必须提供显示额外实参,类模板示例化一个类时,会将模板参数T的每个实例替换为给定的模板实参。

16.11

模板类不是一个类型,当使用它的时候必须给定额外实参

public:
void insert(ListItem<elemType> *ptr,elemType value);
private:
ListItem<elemtType> *front,*end;

16.12

Blob.h

#pragma once
#include<vector>
#include<list>
#include<string>
#include<memory>
template <typename T>
class Blob {
public:
	typedef T value_type;
	typedef typename std::vector<T>::size_type size_type; //vector类型大小
	//构造函数
	Blob();
	Blob(std::initializer_list<T> il);
	//Blob中的元素数目
	size_type size()const { return data->size(); }
	bool empty()const { return data->empty(); }
	//添加和删除元素
	void push_back(const T&t) { data->push_back(t); }
	//移动版本
	void push_back(T&&t) { data->data->push_back(std::move(t)); }
	void pop_back();
	//元素访问
	T &back();
	T& operator[](size_type i);
	const T &back()const;
	const T& operator[](size_type i)const;

private:
	std::shared_ptr <std::vector<T>>data;
	//若data无效,抛出msg
	void check(size_type i, const std::string &msg) const;
};
template <typename T>
void Blob<T>::check(size_type i, const std::string &msg)const
{
	if (i >= data->size())
		throw std::out_of_range(msg);
}
template <typename T>
T& Blob<T>::back()
{
	check(0, "back on empty Blob");
	return data->back();
}
template <typename T>
T& Blob<T>::operator[](size_type i)
{
	check(i, "subscript out of range");
	return (*data)[i];
}
template <typename T>
void Blob<T>::pop_back()
{
	check(0, "pop_back on empty Blob");
	data->pop->back();
}
template <typename T>
const T& Blob<T>::back()const {
	check(0, "back on empty Blob");
	return data->back();
}
template <typename T>
const T& Blob<T>::operator[](size_type i)const {
	check(i, "subscript out of range");
	return (*data)[i];
}
// 构造函数
template <typename T>
Blob<T>::Blob(std::initializer_list <T>il):data(std::make_shared<std::vector<T>>(il)){}

BlobPtr.h

#pragma once
#include"Blob.h"
//首先将这些声明为模板
template <typename >class BlobPtr;
template <typename >class Blob; // 运算符==中的参数需要的
template <typename T>
bool operator==(const Blob<T>&, const Blob<T>&);
template<typename T>
class BlobPtr {
	//每个Blob示例将访问权限授予用相同类型实例化的BLobptr和相等运算符
	friend class BlobPtr(T);
	friend bool operator==<T>
		(const Blob<T>&, const Blob<T>&);
public:
	BlobPtr():curr(0);
	BlobPtr(Blob<T> &a, size_t sz = 0) :wptr(a.data), curr(sz) {}
	T& operator*() const {
		auto p = check(curr, "dereference past end");
		return (*p)[curr];//(*p)为本对象指向的vector
	}
	//递增和递减
	BlobPtr<T> operator++(int);
	BlobPtr<T> operator--(int) :
	BlobPtr& operator++();
	BlobPtr& operator--() :
private:
	//若检查成功,check将返回一个指向vector的shared_ptr
	std::shared_ptr<std::vector<T>> check(std::size_t, const std::string&) const;
	//保存一个weak_ptr,表示底层vector可能被销毁
	std::weak_ptr<std::vector<T>> wptr;
	std::size_t curr; //表示当前位置
};
//后置递增
template<class T>
BlobPtr<T> BlobPtr<T>::operator++(int)
{
	//无需检查,因为调用前置递增是会进行检查
	BlobPtr ret = *this;
	++*this;
	return ret;
}

16.13

一对一的友好关系

16.14&15

Screen.h

#pragma once
#include <string>
#include <iostream>

template<unsigned H, unsigned W>
class Screen {
public:
	typedef std::string::size_type pos;
	Screen() = default;
	Screen(char c) :contents(H* W, c) { }
	char get() const
	{
		return contents[cursor];
	}
	Screen& move(pos r, pos c);
	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(0, W) << std::endl;
		}
		return os;
	}
	friend std::istream& operator>> (std::istream& is, Screen& c)
	{
		char a;
		is >> a;
		std::string temp(H * W, a);
		c.contents = temp;
		return is;
	}
private:
	pos cursor = 0;
	pos height = H, width = W;
	std::string contents;
};
template<unsigned H, unsigned W>
inline Screen<H, W>& Screen<H, W>::move(pos r, pos c)
{
	pos row = r * width;
	cursor = row + c;
	return *this;
}

main.cpp

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

int main()
{
	Screen<5, 5> scr('c');
	Screen<5, 5> scr2;
	std::cout << scr;
	std::cin >> scr2;
	std::cout << scr2;
	return 0;
}

16.16

#pragma once
#include <iostream>
#include<initializer_list>
using namespace std;
template<class T>
class Vec;
template<class T>
bool operator== (const Vec<T>& lhs, const Vec<T>& rhs);
template<class T>
bool operator!= (const Vec<T>& lhs, const Vec<T>& rhs);
template<class T>
bool operator> (const Vec<T>& lhs, const Vec<T>& rhs);
template<class T>
bool operator< (const Vec<T>& lhs, const Vec<T>& rhs);
template<typename T>
class Vec
{
    friend bool operator==<T> (const Vec<T>& lhs, const Vec<T>& rhs);
    friend bool operator!=<T> (const Vec<T>& lhs, const Vec<T>& rhs);
    friend bool operator><T> (const Vec<T>& lhs, const Vec<T>& rhs);
    template<typename T> friend bool operator<  (const Vec<T>& lhs, const Vec<T>& rhs);
public:
    Vec() : elements(nullptr), first_free(nullptr), cap(nullptr) {};
    Vec(initializer_list<T>il)
    {
        auto data = alloc_n_copy(il.begin(), il.end());
        elements = data.first;
        first_free = cap = data.second;
    }
    Vec(const Vec&);
    Vec(Vec&& vec)noexcept :elements(vec.elements), first_free(vec.first_free), cap(vec.cap)
    {
        vec.elements = vec.first_free = vec.cap = nullptr;
    }
    Vec& operator=(Vec&& rhs)noexcept
    {
        if (this != &rhs)
        {
            free();
            elements = rhs.elements;
            first_free = rhs.first_free;
            cap = rhs.cap;
            rhs.elements = rhs.first_free = rhs.cap = nullptr;
        }
        return *this;
    }
    ~Vec();
    Vec& operator=(initializer_list<T>);
    Vec& operator= (const Vec&);
    T& operator[](size_t n);
    const T& operator[](size_t n)const;
    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, const T& s = " ");
private:
    static allocator<T> alloc;
    void chk_n_alloc()
    {
        if (size() == capacity())reallocate();
    }
    pair<T*, T*> alloc_n_copy(const T*, const T*);
    void free();
    void reallocate();
    T* elements;
    T* first_free;
    T* cap;
};
template<typename T>
allocator<T> Vec<T>::alloc;
template<typename T>
pair<T*, T*> Vec<T>::alloc_n_copy(const T* b, const T* e)
{
    auto  data = alloc.allocate(e - b);
    return pair<T*, T*>(data, uninitialized_copy(b, e, data));
}
template<typename T>
void Vec<T>::free()
{
    if (elements) {
        auto b = first_free;
        while (b != elements)
        {
            alloc.destroy(--b);
        }
        alloc.deallocate(elements, cap - elements);
    }
}
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++, move(*elem++));
    }
    elements = newdata;
    first_free = dest;
    cap = elements + newcapacity;
}
template<typename T>
Vec<T>::Vec(const Vec& s)
{

    auto data = alloc_n_copy(s.begin(), s.end());
    elements = data.first;
    first_free = cap = data.second;
}
template<typename T>
Vec<T>& Vec<T>::operator=(const Vec& rhs)
{
    auto data = alloc_n_copy(rhs.begin(), rhs.end());
    free();
    elements = data.first;
    first_free = cap = data.second;
    return *this;
}
template<typename T>
void Vec<T>::push_back(const T& s)
{
    chk_n_alloc();
    alloc.construct(first_free++, s);
}
template<typename T>
Vec<T>::~Vec()
{
    free();
}
template<typename T>
void Vec<T>::reserve(size_t n)
{
    if (n < size())return;
    auto newcapacity = n;
    auto newdata = alloc.allocate(newcapacity);
    auto dest = newdata;
    auto elem = elements;
    for (size_t i = 0; i < size(); i++)
    {
        alloc.construct(dest++, move(*elem++));
    }
    elements = newdata;
    first_free = dest;
    cap = elements + newcapacity;
}
template<typename T>
void Vec<T>::resize(size_t n, const T& s)
{

    if (n > size()) {
        if (n > capacity()) {
            reserve(n);
        }

        for (size_t i = size(); i < n; ++i) {
            alloc.construct(first_free++, s);
        }
    }
    else if (n < size()) {
        while ((elements + n) != first_free) {
            alloc.destroy(--first_free);
        }
    }
}

template<typename T>
T& Vec<T>::operator[](size_t n)
{
    return elements[n];
}
template<typename T>
const T& Vec<T>::operator[](size_t n)const
{
    return elements[n];
}
template<typename T>
Vec<T>& Vec<T>::operator=(initializer_list<T>il)
{
    auto p = alloc_n_copy(il.begin(), il.end());
    free();
    elements = p.first;
    first_free = cap = p.second;
    return *this;
}
template<typename T>
bool operator== (const Vec<T>& lhs, const Vec<T>& rhs)
{
    if (lhs.size() != rhs.size()) {
        return false;
    }
    else {
        auto l_iter = lhs.begin();
        auto r_iter = rhs.begin();
        for (l_iter, r_iter; l_iter != lhs.end(); ++l_iter, ++r_iter) {
            if (*l_iter != *r_iter) {
                return false;
            }
        }
    }
    return true;
}
template<typename T>
bool operator!= (const Vec<T>& lhs, const Vec<T>& rhs)
{
    return !(lhs == rhs);
}
template<typename T>
bool operator<(const Vec<T>& lhs, const Vec<T>& rhs)
{
    return lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
}
template<typename T>
bool operator>(const Vec<T>& lhs, const Vec<T>& rhs)
{
    return lexicographical_compare(rhs.begin(), rhs.end(), lhs.begin(), lhs.end());
}


16.17

当我们希望通知编译器一个名字表示类型时,必须用关键字typename,而不是class.

16.18

(a) 非法,U前面加typename
(b) 非法,T为类型
© 非法,内敛说明符放到尖括号之后
(d) 非法,没有说明返回类型
(e) 合法,会隐藏掉外部的声明。

template <typename T, typename U, typename V> void f1(T, U, V);
template <typename T> T f2(T&);
template <typename T> inline T foo(T, unsigned int*);
template <typename T> T f4(T, T);
typedef char Ctype;
template <typename Ctype> Ctype f5(Ctype a);

16.19

#include<vector>
#include<iostream>
template <typename T>
void printVec(T&t)
{
	for (auto i : t)
		std::cout << i << " ";
	std::cout << std::endl;
}
int main()
{
	std::vector<int> v = { 1,2,34,5,6,7,7 };
	printVec(v);
	return 0;
}

16.20

#include<vector>
#include<iostream>
template <typename T>
void printVec(T&t)
{
	for (auto i=t.begin();i!=t.end();++i)
		std::cout << *i << " ";
	std::cout << std::endl;
}
int main()
{
	std::vector<int> v = { 1,2,34,5,6,7,7 };
	printVec(v);
	return 0;
}

16.21

#pragma once
#include<iostream>
#include<memory>
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;
};

16.22&23

16.24

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

16.25

声明,不会在本文件中生成实例代码
定义,编译器将会生成代码。

16.26

不能。因为vector类在使用默认构造函数实例化时,会要求类型T必须有默认构造函数。如果类型T没有默认构造函数,实例化会导致编译错误。因此,对于没有默认构造函数的类NoDefault,我们无法使用vector进行显式实例化。

16.27

(a)(b)©(f)发生了各自类型的实例化;
(e)(d)未发生实例化,在他们之前实例化已经完成。

16.31

shared_ptr是运行时绑定删除器,而unique_ptr则是编译时绑定删除器.
unique_ptr有两个模板参数,一个是所管理的对象类型.另一个是删除器类型.因此,删除器类型是unique_ptr类型的一部分,在编译时就可知道.删除器可直接保存在unique_ptr对象中.通过这种方式,unique_ptr避免了间接调用删除器的运行时的开销.而编译时还可以将自定义的删除器,如DebugDelete编译为内联形式.

16.32

在模板实参推断过程中,编译器使用函数调用中的实参类型来寻找模板实参,用这些模板实参生成的函数版本与给定的函数调用最为匹配。

16.33

1.const转换,将非const对象的引用或指针传递给一个const的引用或指针形参。
2.数组或函数指针转换:如果函数形参不是引用类型,可以对数组或者函数类型的实参应用正常的指针变换

16.34

(a)不合法,模板类型是引用,数组不能转换为指针
(b)合法,两个数组大小是相同的

16.35

(a)合法,char
(b)合法,double
©合法,const char
(d)不合法,二义性

16.36

​ (a)合法,T被推断为int*
​ (b)合法,T1和T2都被推断为int *
​ ©合法,T被推断为const int *
​ (e)非法,T被推断为int *或是const int *,都不能匹配调用
​ (f)合法,T1被推断为int *,T2被推断为const int *

16.37

可以,显示指定的实参

16.38

在调用make_shared时,有时不给出参数,表示进行值初始化,有时给出的参数与维护的动态对象的类型不相关,因此,编译器无法从参数推断模板类型.就需要显示指定模板实参.

16.39

compare<string>("Hello","World");

16.40

合法,需要指向的类型支持整型的加法。

16.41

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

16.42

(a)T:int& val:int&
(b)T:const int& val:const int&
©T:int val:int&&

16.43

T:int&

16.44

声明为T:
(a)int
(b)int
©int
因为为值传递
声明为const T&:
(a)int
(b)int
©int

16.45

用字面值常量调用g会实例化,因此正确;
用int调用g会实例化,显然会生成int&类型的vector,错误。

16.46

std::move()通过上面提到的static_cast将左值引用强制转换为右值.

16.47

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

16.48

#pragma once
#include<string>
#include<iostream>
using namespace std;
template <typename T> std::string Debug_rep(const T& t);
template <typename T> std::string Debug_rep(T* p);
string Debug_rep(const std::string& s);
string Debug_rep(char* p);
string Debug_rep(const char* p);

template<typename T>
string Debug_rep(const T& s)
{
	ostringstream ret;
	ret << s << endl;
	return ret.str();
}
template<typename T>
string Debug_rep(T* s)
{
	ostringstream ret;
	cout << "pointer:" << s << endl;
	if (s)
		cout << Debug_rep(*p) << endl;
	else
		cout << "null pointer" << endl;
}
string Debug_rep(const string& s)
{
	return " " + s + " ";
}
string Debug_rep(char* p)
{
	return Debug_rep(string(p));
}
string Debug_rep(const char* p)
{
	return Debug_rep(string(p));
}

16.49

g(42) T=int;
g§ T=int;
g(ci) T=const int;
g(p2) T=const int;
f(42) T=int;
f§ T=int*;
f(ci) T=const int;
f(p2) T=const int;

16.50



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

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

template <typename T> void f(const T*)
{
	std::cout << "f(const T*)\n";
}
template <typename T> void g(T)
{
	std::cout << "template <typename T> void g(T)\n";
}
template <typename T> void g(T*)
{
	std::cout << "template <typename T> void g(T*)\n";
}
int main()
{
	int i = 42, *p = &i;
	const int ci = 0, *p2 = &ci;

	//g(42);    //template <typename T> void g(T ); --is called
	//g(p);     //template <typename T> void g(T*); --is called
	//g(ci);      //template <typename T> void g(T)   --is called
	//g(p2);      //template <typename T> void g(T*)    --is called
	//f(42);    //f(T)
	//f(p);     //f(T)
	//f(ci);    //f(T)
	f(p2);      //f(const T*)
}

16.51&52

#include <iostream>
template<typename T, typename ...Args>
void foo(T t, Args ...args)
{
    std::cout << sizeof...(Args) << std::endl;
    std::cout << sizeof...(args) << std::endl;
}
int main()
{
        int i = 0;
        double d = 3.14;
        std::string s = "how";
        foo(i, s, 42, d);       // sizeof...(Args)=3  sizeof...(args)=3
        foo(s, 42, "hi");       // sizeof...(Args)=2  sizeof...(args)=2
        foo(d, s);              // sizeof...(Args)=1  sizeof...(args)=1
        foo("hi");              // sizeof...(Args)=0  sizeof...(args)=0
        foo(i, s, s, d);        // sizeof...(Args)=3  sizeof...(args)=3

}

16.53

#include <iostream>
#include <string>
using namespace std;
template<typename T>
ostream &print(ostream &os, const T&t) {
	return os << t;
}
template <typename T, typename ...Args>
ostream &print(ostream &os,const T&t,const Args&...rest)
{
	os << t << " ";
	return print(os, rest...);
}

int main()
{
	int a = 10;
	double b = 10.11;
	string c = "abecd";
	print(cout,a, b, c);
	return 0;
}

16.54

代码	说明	文件	行	禁止显示状态
C2679	二进制“<<: 没有找到接受“const T”类型的右操作数的运算符(或没有可接受的转换)		

16.55

“print”: 未找到匹配的重载函数和“std::ostream &print(std::ostream &,const T &,const Args…): 应输入 3 个参数,却提供了 1

16.56

debug_rep.h

#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(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)
{
	return debug_rep(std::string(p));
}

main.cpp

#include <iostream>
#include <string>
#include<vector>
#include"debug_rep.h"
using namespace std;
template<typename T>
ostream &print(ostream &os, const T&t) {
	return os << t;
}
template <typename T, typename ...Args>
ostream &print(ostream &os,const T&t,const Args&...rest)
{
	os << t << " ";
	return print(os, rest...);
}
template<typename T>
ostream &print(ostream &os, const T&t);
template<typename ...Args>
ostream &errorMsg(ostream &os, const Args&...rest)
{
	return print(os, debug_rep(rest)...);
}
int main()
{
	int a = 10;
	double b = 10.11;
	string c = "abecd";
	errorMsg(cerr,a, b, c);
	return 0;
}

16.57

可变参数版本的代码灵活,可以使用不同类型的参数,但是代码比较复杂,不方便调试;
原版的使用initializer_list,只能接受同一种类型元素例如string,或者是可以转换的类型。

16.58

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

16.59

首先chk_n_alloc()检查内存空间是否足够,不够重新分配内存空间;
然后调用construct在first_free指向的位置创建一个元素,由于s是左值,传入后由于实参为右值引用,所以叠加以后还是一个左值;
一个左值参数调用construct,将会调用拷贝构造函数创建一个string。

16.60

make_shared函数是一个可变参数模板,它会把参数转发给初始化对象的构造函数,通过动态分配内存空间创建一个指针,在最后将原始指针包装为shared_ptr返回。

16.61

template<typename T,typename ...Args>
shared_ptr<T> Make_shared(Args&&...args)
{
    return shared_ptr<T>(new T(forward<Args>(args)...));
}

16.62

namespace std {
	class  hash<Sales_data> {
		typedef size_t result_type;
		typedef Sales_data argument_type;
		size_t operator()(const Sales_data& s) {
			return hash<string>()(s.bookNo)^hash<unsigned>()(s.units_sold)^hash<double>()(s.revenue);
		}
	}
}

16.63&64

#include<vector>
#include<iostream>
#include<string>
using namespace std;
template<typename T>
size_t cnt(const vector<T>&v,T t)
{
	size_t res = 0;
	for (auto i : v) {
		if (i == t)
			++res;
	}
	return res;
}
template<>
size_t cnt(const vector<const char *>&v, const char*t)
{
	size_t res = 0;
	for (auto c : v) {
		if (strcmp(c, t) == 0)
			++res;
	}
	cout << "特例化调用" << endl;
	return res;
}

int main()
{
	vector<int> v = { 1,2,3,4,5,6,7 };
	vector<string> str = { "aaa","bbb","ccc" };
	vector<const char*> cs = { "aaa","bbb","ccc" };
	cout << cnt(v, 1)<<endl;
	cout << cnt(str, string("aaa")) << endl;
	cout << cnt(cs, "aaa") << endl;

}

16.65

template<typename T>
string Debug_rep(const char* s)
{
    string ret(s);
    return s;
}
template<typename T>
string Debug_rep( char* s)
{
    string ret(s);
    return s;
}

16.66

重载有可能会改变匹配顺序,但是不会发生匹配错误,缺点是要写的太多;
特例化不会改变顺序,但是可能发生匹配错误。

16.67

不会,因为特例化版本只是当前模板的一个独立的定义,本质是一个实例,而非函数名的一个重载版本。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值