C 11学习笔记 15

发布 2021-05-12 14:37:28 阅读 2986

面向对象编程和泛型编程都能处理在编写程序时不知道类型的情况。不同之处:oop能处理类型在程序运行之前都未知的情况;而泛型编程中,在编译时就能获知类型了。

模板参数类别不能为空。

模板参数表示在类或函数定义中用到的类型或值。

template

int compare(const t &v1 , const t &v2)

if(v1 if(v2 return 0 ;

cout<编译器生成的版本通常被称为模板的实例。

特别是,类型参数可以用来指导返回类型或函数参数类型,以及在函数内用于变量声明或类型转换:

类型参数前必须加上class或typename(typename是在模板已经广泛使用之后才引入c++语言的)

非类型行参数必须是常量表达式:template

当一个模板实例化时,非类型参数被一个用户提供的或编译器推导出来的值所代替。

一个非类型参数可以是一个整型,或者是一个指向对象或函数类型的指针或(左值)引用。绑定到非类型参数的实参时一个常量表达式。绑定到指针或引用非类型参数的实参必须具有静态的生存期。

指针参数也可以用nullptr或一个值为0的常量表达式来实例化。

函数模板可以声明成inline或constexptr

template inline t min(const t&, const t&);

compare函数说明了编写泛型**的两个重要原则:

模板中的函数参数是const的引用。

函数体中的条件判断仅使用《比较运算。

通过将函数参数这位const引用,我们保证函数可以用于不能拷贝的类型。而且,处理大对象,这种设计策略还能使函数运行得更快。

只使用小于,降低了对处理对象的类型要求,不用支持》

是实际上,如果真的关系类型无关和可移植性,可能需要用less来定义,(不用less,存在的问题是,如果用户调用它比较两个指针,二期两个指针为指向相同的数组,则**的行为未定义。

template int compare(const t &v1, const t &v2)

if(less()(v1,v2)) return -1;

if(less()(v2,v1)) return 1;

return 0;

模板程序应该尽量减少对实参类型的要求。

当编译器遇到一个模版定义是,它并不生成**。只有当我们实例化出模板的一个特定版本时,编译器才会生成**。当我们使用(而不是定义)模板是,编译器才生成**。

通常,当我们调用一个函数时,编译器只需要掌握函数的声明。类似的,当我们使用类对象时,类定义必须是可用的,但是成员函数的定义不必已经出现。因此,我们将类定义和函数声明放在头文件中,而将普通函数和类的成员函数的定义放在源文件中。

但是模板不同:为了生成一个实例化版本,编译器需要掌握函数模板或类模板成原函数的定义。因此,模板的头文件通常即包含声明也包含定义。

当使用模板是,所有不依赖模板参数的名字都必须是可见的,这是有模板的提供者来保证的。而且,模板的提供者必须保证,当模板被实例化时,模板的定义包括类模板的成员定义都是可见的。

用来实例化模板的所有函数、类型以及与类型关联的运算符的声明都必须是可见的,这是由模板的用户来保证的。。

模板知道实例化是才会生成**,这一特性影响了我们何时才会获知模板内**的编译错误。通常编译器在三个阶段报告错误。

第一阶段是编译模板本身时。在这个阶段,编译器通常不会发现很多错误。编译器可以检查语法错误。

第二阶段是编译器遇到模板使用时。在此阶段,编译器仍然没有很多课检查的。对于函数模板调用,编译器通常会检查实参数目是否正确。

它还检查参数类型是否匹配。对于类模板,编译器可以检查用户是否提供了正确数目的模板实参。

第三个阶段是模板实例化时,只有在这个阶段才能发现类型相关的错误。依赖于编译器如何管理实例化,这类错误可能在链接是才报告。

编译器不能为类模板推断模板参数类型。必须使用尖括号中提供的额外信息。

template class blob(

public:

typedef t value_type;

typedef typename std::vector::size_tyep size_type;

blob();

blob(std::initializer_list il);

size_type size( )cosnt

bool empty( )const

void push_back(const t &t)

void push_back(t &&t)

void pop_back();

t& back();

t& operator size_type i);

private:

std::shared_ptr> data;

void check(size_type i, const std::string &msg) const;

一个类模板的每个实例都是一个相互独立的类。

应该记住类模板的名字不是一个类型名,而是用来实例化类型,而一个实例化的类型总是包含模板参数的。

一个模板中的**若果使用了另一个模板,我们通常将模板自己的参数作为被使用模板的实参。

std::shared_ptr> data;

类模板的成员函数本身是一个普通函数。但是,类模板的每个实例都有其自己版本的成员函数。因此,类模板的成员函数具有和模板相同的模板参数。

因而,定义在类模板之外的成员函数就必须以关键字template开始,后接类模板参数列表。

template

void blob::check(size_type i, const std::string &msg)const

if (i >=data->size( )

throw std::out_of_range(mag);

template

t& blob::back( )

check(0 , back on empty blob");

return data->back( )

template

t& blob:: operator[ ]size_type i)

check(i , subscript out of range");

return (*data)[i];

template

blob::blob( )data(std::make_shared>(

template

blob::blob(std::initializer_list il) :data(std::make_shared> (il))

在默认情况下,对于一个实例化了的类模板,其成员只有在使用时才被实例化。

当我们使用一个类模板类型时必须提供模板实参,但这一规则有一个例外。在类模板自己的作用域中,我们可以直接使用模板名而不提供实参,当我们处于一个类模板的作用域中时,编译器处理模板自身引用时就好像我们已经提供了与模板参数匹配的实参一样。

template class blobptr

blobptr(blob &a, size_t sz = 0) :wptr( curr(sz)

t& operator*( const

//注意这里没有模板参数。

blobptr& operator++(

blobptr& operator--(

private:

std::shared_ptr> check (std::size_t ,cosnt std::string&) const;

std::weak_ptr> wptr;

std::size_t curr;

当我们在类模板外定义其成员是,必须记住,我们并不在类的作用域中,知道遇到类名才表示进入类的作用域:

template

blobptr& blobptr::operator++(int)

blobptr ret = this ;

++ this;

return ret;

当一个类包含一个友元声明时,类与友元各自是否是模板是相互无关的。如果一个类模板包含一个非模板友元,则友元被授权可以访问所有模板实例。如果友元是模板,类可以授权给所有友元模板实例,也可以只授权给特定实例。

类模板与另一个模板友好关系最常见的形式是建立对应实例及其友元间的友好关系。

为了引用模板的一个特定实例,我们必须首先声明模板自身。

template class blobptr;

C11学习笔记 5

参数传递时,如果是引用类型,它将绑定到对应的实参上,否者,将实参的值拷贝后赋给形参。引用可避免拷贝,如果不需要改变参数,最好定义成常量引用。和其他初始化一样,当用实参初始化时会忽略顶层const,当形参有顶层const时,传给它常量对象或非常量对象都可以。我们可以用非常量初始化一个底层const对象...

C 11学习笔记 11

动态分配的内存,只有在显式释放是,这些对象才会销毁。但是标准库中的两智能指针可以确保自动释放。除了静态内存和栈内存,每个程序还拥有一个内存池。这部分内存被称作自由空间或堆。静态内存用来保存局部static对象 类static数据成员以及定义在任何函数之外的变量。栈内存用来保存定义在函数没得非stat...

C 11学习笔记 16

tuple是类型pair的模板。不同tuple类型的成员类型也不同,但一个tuple可以有任意数量的成员。每个确定的tuple类型的成员数目是固定的。当我们希望将一些数据组合成单一对象,但有不想麻烦地定义一个新数据结构来表示时,tuple是非常有用的。快速而随意 的数据结构 tuple类型及其伴随类...