当前位置: 首页 > news >正文

淘宝客网站开发平台网站页面设计工具

淘宝客网站开发平台,网站页面设计工具,广告公司网站设计策划书,建设银行网银盾连接不上网站类模板(参考《C Templates 英文版第二版》) Chapter 1 类模板 与函数相似,类也可以被一个或者多个类型参数化 在这章,我们使用栈作为例子 2.1 类模板stack的实现 #include vector #include casserttemplatetypename T class Stack { private:std…类模板(参考《C Templates 英文版第二版》) Chapter 1 类模板 与函数相似,类也可以被一个或者多个类型参数化 在这章,我们使用栈作为例子 2.1 类模板stack的实现 #include vector #include casserttemplatetypename T class Stack { private:std::vectorT elems;public:void push(T const elem);void pop();T const top() const;bool empty() const{return elems.empty();} };template typename T void StackT::push(T const elem) {elems.push_back(elem); }template typename T void StackT::pop() {assert(!elems.empty());elems.pop_back(); }template typename T T const StackT::top() const {assert(!elems.empty());return elems.back(); }这个类模板通过一个STL里面的类模板vector实现.这样,我们就不用去实现内存管理,拷贝构造,赋值运算符等内容,专注于类的实现 2.1.2 成员函数的实现 如果你要定义一个类模板的成员函数,你必须去指定他是一个模板,并且满足类模板的全部类型,就像下面这样: void StackT::push(T const elem) {elems.push_back(elem); }在这种情况下,push_back()被调用,向vector添加一个elem 注意:pop_back()函数只移除最后一个元素,但是不返回它,只是因为这种行为(只移除)是异常安全的,是不可能实现一个移除并返回最后一个元素的异常安全函数的1 2.2 stack实用类模板 #include max1.hpp #include iostream #include string #include format #include type_traits #include stack1.hpp #include iostream #include stringint main() {Stackint intStack; // stack of intsStackstd::string stringStack; // stack of strings// manipulate int stackintStack.push(7);std::cout intStack.top() \n;// manipulate string stackstringStack.push(hello);std::cout stringStack.top() \n;stringStack.pop(); }C17可以这么写2 #include vector int main() {std::vector intVector{ 1,2 }; //省略 }注意:类模板只会实例化被调用的函数,再上个例子中,int string的top(),push()都被实例化,但是pop()只在传入string实例化一次 2.3 类模板的部分使用(Partial Usage of Class Templates) 一个类模板通常对模板参数提供多种操作,这可能会给你错觉:类模板必须提供模板参数所有成员函数的操作. 但事实上不是这样,类模板只会提供被模板参数用到的成员函数 在上文中加入以下代码: void printOn(std::ostream strm){for (T const elem : elems){strm elem std::endl;}}运行: Stackstd::pairint, int ps;ps.push({ 2,5 });ps.push({ 3,5 });std::cout ps.top().first std::endl; //正确//ps.printOn(std::cout); // 错误只有当你调用printOn()时,才会报错,说明类模板只会实例化需要的成员函数, 2.3.1 概念(Concepts) 类模板、函数模板及非模板函数常为类模板成员可以与制约关联制约指定模板实参上的要求这能用于选择最准确的函数重载和模板特化。 制约亦可用于限制变量声明和函数返回类型中的自动类型推导为只有满足指定要求的类型。 这种要求的具名集合被称为概念。每个概念都是谓词于编译时求值并成为模板接口的一部分它在其中用作制约 #include locale #include string using namespace std::literals;// 概念 EqualityComparable 的声明任何有该类型值 a 和 b // 而表达式 ab 可编译而其结果可转换为 bool 的 T 类型满足它 template typename T concept bool EqualityComparable requires(T a, T b) {{a b} - bool; };void f(EqualityComparable); // 有制约函数模板的声明 // templatetypename T // void f(T) requires EqualityComparableT; // 相同的长形式int main() {f(abcs); // OK std::string 为 EqualityComparablef(std::use_facetstd::ctypechar(std::locale{})); // 错误非 EqualityComparable }更多请参见:制约与概念 - cppreference.com 2.4 友元 与其使用printOn函数打印元素不如重载operator然而通常operator会实现为非成员函数。下面在类内定义友元它是一个普通函数 templatetypename T class Stack {...void printOn(std::ostream os) const;friend std::ostream operator(std::ostream os, const StackT stack){stack.printOn(os); return os;} };如果在类外定义友元类模板参数不可见事情会复杂很多 templatetypename T class Stack {...friend std::ostream operator(std::ostream, const StackT); };std::ostream operator(std::ostream os,const StackT stack) // 错误类模板参数T不可见 {stack.printOn(os);return os; }有两个解决方案: 一是隐式声明一个新的函数模板并使用不同的模板参数 templatetypename T class Stack {… templatetypename U friend std::ostream operator(std::ostream, const StackU); };// 类外定义 templatetypename U std::ostream operator(std::ostream os, const StackU stack) {stack.printOn(os);return os; }二是将友元前置声明为模板而友元参数中包含类模板这样就必须先前置声明类模板 templatetypename T // operator中参数中要求Stack模板可见 class Stack;templatetypename T std::ostream operator(std::ostream, const StackT);// 随后就可以将其声明为友元 templatetypename T class Stack {…friend std::ostream operator T (std::ostream, const StackT); };// 类外定义 templatetypename T std::ostream operator(std::ostream os, const StackT stack) {stack.printOn(os);return os; } 同样函数只有被调用到时才实例化元素没有定义operator时也可以使用这个类只有调用operator时才会出错 Stackstd::pairint, int s; // std::pair没有定义operator s.push({1, 2}); // OK s.push({3, 4}); // OK std::cout s.top().first s.top().second; // 34 std::cout s \n; // 错误元素类型不支持operator2.5 类模板特化 模板的实际应用中有一些概念和应用很容易让人混淆现在就分析一下模板的特化和实例化。编写模板的代码最终的目的是应用而在实际应用的过程中大家最经常使用的是模板的实例化。也就是说模板说一族类或函数的抽象那么要使用它就需要把它应用到某个具体的类或者函数上。 另外还有一个绕不开的就是特化specialization,从目前的教材来看有两种理解 凡是把模板用具体的值来替代的过程都叫特化。如果这么理解实例化也是特化的一种。特化是普通模板通过具体的值来替换后不能满足一些特定的情况下的要求需要对其进行特别的处理包括偏特化和全特化。 全特化写法 template class Stackstd::string {... }; 实例: #include stack1.hpp #include deque #include string #include casserttemplate class Stackstd::string {private:std::dequestd::string elems; // elementspublic:void push(std::string const); // push elementvoid pop(); // pop elementstd::string const top() const; // return top elementbool empty() const { // return whether the stack is emptyreturn elems.empty();} };void Stackstd::string::push (std::string const elem) {elems.push_back(elem); // append copy of passed elem }void Stackstd::string::pop () {assert(!elems.empty());elems.pop_back(); // remove last element }std::string const Stackstd::string::top () const {assert(!elems.empty());return elems.back(); // return copy of last element } 当我们使用std::string作为模板参数时,就会实例化这个用std::string特化的类. 我的理解:模板的特化就是为了处理一些非一般情况 2.6 偏特化 函数是没有偏特化的。所以这里只是介绍类的偏特化。所谓偏特化又叫局部特化或者部分特化也就是在特定的条件下使用特定的对象来替换模板参数但又不能完全替换 #include stack1.hpp// partial specialization of class Stack for pointers: templatetypename T class StackT* {private:std::vectorT* elems; // elementspublic:void push(T*); // push elementT* pop(); // pop elementT* top() const; // return top elementbool empty() const { // return whether the stack is emptyreturn elems.empty();} };templatetypename T void StackT*::push (T* elem) {elems.push_back(elem); // append copy of passed elem }templatetypename T T* StackT*::pop () {assert(!elems.empty());T* p elems.back();elems.pop_back(); // remove last elementreturn p; // and return it (unlike in the general case) }templatetypename T T* StackT*::top () const {assert(!elems.empty());return elems.back(); // return copy of last element } 使用 templatetypename T class StackT* {}我们定义了一个类模板 T仍然是模板参数,但是为了T*特化 具有多个参数的部分特化 templatetypename T1, typename T2 class MyClass { … };// partial specialization: both template parameters have same type templatetypename T class MyClassT,T { … }; // partial specialization: second type is int templatetypename T class MyClassT,int { … };// partial specialization: both template parameters are pointer types templatetypename T1, typename T2 class MyClassT1*,T2* { … };MyClass int, float mif; // uses MyClassT1,T2 MyClass float, float mff; // uses MyClassT,T MyClass float, int mfi; // uses MyClassT,int MyClass int*, float* mp; // uses MyClassT1*,T2*如果有多个模板匹配,就会歧义: MyClass int, int m; // ERROR: matches MyClassT,T and MyClassT,int MyClass int*, int* m; // ERROR: matches MyClassT,T and MyClassT1*,T2*2.7 默认模板参数 对类模板,你可以设置一个默认模板参数,例如,对于Stack你可以设置一个默认模板参数管理内容 templatetypename T, typename Cont std::vectorT class Stack {private:Cont elems; // elementspublic:void push(T const elem); // push elementvoid pop(); // pop elementT const top() const; // return top elementbool empty() const { // return whether the stack is emptyreturn elems.empty();} };templatetypename T, typename Cont void StackT,Cont::push (T const elem) {elems.push_back(elem); // append copy of passed elem }templatetypename T, typename Cont void StackT,Cont::pop () {assert(!elems.empty());elems.pop_back(); // remove last element }templatetypename T, typename Cont T const StackT,Cont::top () const {assert(!elems.empty());return elems.back(); // return copy of last element } 这个例子就是使用std::vector作为默认内容管理器 注意:这个类现在有两个模板参数,所以每个成员函数也应该有两个模板参数 int main() {// stack of ints:Stackint intStack;// stack of doubles using a std::deque to manage the elementsStackdouble,std::dequedouble dblStack;// manipulate int stackintStack.push(7);std::cout intStack.top() \n;intStack.pop();// manipulate double stackdblStack.push(42.42);std::cout dblStack.top() \n;dblStack.pop(); } 这样Stackint intStack;使用std::vector管理元素,你也可以自定义管理器Stackdouble,std::dequedouble dblStack; 2.8 类型别名 为整个类型定义一个新名字让类模板更方便使用 通过使用using using IntStack Stack int; // alias declaration void foo (IntStack const s); // s is stack of ints IntStack istack[10]; // istack is array of 10 stacks of intsusing IntStack Stack int;这样你就可以为整个类型定义一个别名,更方便使用 由于模板不是一个类型所以不能定义一个typedef引用一个模板但是新标准(since C11)允许使用using为类模板定义一个别名 以Stack使用std::deque管理元素为例 templatetypename T using DequeStack StackT, std::dequeT;这样我们就可以使用DequeStackint 代替 Stackint,std::dequeint,这两个表达的完全相同 2.9 类模板参数推断 在C17之前,你必须传入所有的模板参数类型,但是,C17之后,这个限制放松了,如果能通过构造函数推断出模板参数类型,你可以不用明确的指定参数类型 Stack int intStack1; // stack of strings Stack int intStack2 intStack1; // OK in all versions Stack intStack3 intStack1; // OK since C17构造函数: templatetypename T class Stack { private: std::vectorT elems; // elementspublic: Stack () default; Stack (T const elem) // initialize stack with one element: elems({elem}) { }… };你可以这样声明一个Stack: Stack intStack 0; // Stackint deduced since C17通过用整初始化Stack推断出模板参数T为int从而实例化一个Stackint 原则上也可以传递字符串字面值常量但这样会造成许多麻烦。用引用传递模板类型T的实参时模板参数不会decay最终得到的类型是原始数组类型 Stack stringStack bottom; // Stackchar const[7] deduced since C17传值的话则不会有这种问题模板实参会decay原始数组类型会转换为指针 templatetypename T class Stack {public:Stack(T x) : v({x}) {}private:std::vectorT v; };Stack stringStack bottom; // Stackconst char* deduced since C17传值时最好使用std::move以避免不必要的拷贝 templatetypename T class Stack {public:Stack(T x) : v({std::move(x)}) {}private:std::vectorT v; };**推断指引(**Deduction Guides) 如果构造函数不想使用传值方式声明,也有其他的解决办法, 你可以定义一个专用的类型指引,将C字符串推断为std::string Stack( char const*) - Stackstd::string;这个指引必须出现在类定义的块,或者命名空间里 Stack(const char*) - Stackstd::string; Stack stringStack{bottom}; // OK: Stackstd::string deduced since C17但由于语法限制,下面这种方法不可以 Stack stringStack bottom; // Stackstd::string deduced, but still not valid因为不能使用拷贝构造() 传递一个字符串去构造一个std::string. 你可以这样: Stack stack2{stringStack}; // Stackstd::string deduced Stack stack3(stringStack); // Stackstd::string deduced Stack stack4 {stringStack}; // Stackstd::string deduced2.10 模板化聚合Templatized Aggregates 聚合类也能作为模板 templatetypename T struct A {T x;std::string s; };这样可以为了参数化值而定义一个聚合它可以像其他类模板一样声明对象同时当作一个聚合使用 Aint a; a.x 42; a.s initial value;C17中可以为聚合类模板定义deduction guide templatetypename T struct A {T x;std::string s; };A(const char*, const char*) - Astd::string;int main() {A a { hi, initial value };std::cout a.x; // hi }没有deduction guide初始化就无法进行因为A没有构造函数来推断。std::array也是一个聚合元素类型和大小都是参数化的C17为其定义了一个deduction guide namespace std { templatetypename T, typename... U array(T, U...)- arrayenable_if_t(is_same_vT, U ...), T, (1 sizeof...(U)); }std::array a{ 1, 2, 3, 4 }; // 等价于 std::arrayint, 4 a{ 1, 2, 3, 4 };累死了,中秋还在肝… 参考解答: GotW #8: CHALLENGE EDITION: Exception Safety ↩︎ C17之后,如果参数类型可以从构造函数推断出来,可以跳过写模板参数即 ↩︎
http://www.yutouwan.com/news/11412/

相关文章:

  • 什么网站可以免费发广告网站建设都用哪些软件
  • 网站没内容wordpress笔记主题
  • 博乐建设工程信息网站如何运营垂直网站
  • 商品网站怎么做google优化排名
  • 合肥网络公司seo建站织梦教程网
  • 额敏网站建设网络服务提供者知道或者应当知道网络用户
  • 吴江seo网站优化软件医院网站建设与管理ppt
  • dw网站模版pmp培训
  • 农业基本建设项目信息网站产品推广方式
  • 网站建设手机版js网站建设
  • 一键网站建设建筑工程网官网平台
  • 微餐饮网站建设平台用哪个网站做相册视频
  • 迅速提高网站排名网站建成后 再添加小功能麻烦吗
  • 旅游网网站建设的管理财务公司
  • 顺德网站制作案例信息河南网站seo费用
  • 网站建设首选-云端高科建设网企业沟通平台
  • 企业网站设计费做哪个科目织梦网站模板怎么做
  • 杭州电商网站平台开发公司django做的电子商务网站
  • 关键词排名优化网站建设公司哪家好网站建设项目分析
  • 如何编辑网站后台职业做网站游戏的
  • 做网站下载功能crm软件系统的构成包括
  • 个人建立网站要多少钱wordpress怎么入驻写模板
  • 网站建设的目标和需求河南省建设工程信息网推荐中项网
  • 网站开发 大学专业深圳大型网站建设公司
  • 做外贸常用的网站有哪些网页制作软件免费版下载
  • vs音乐网站开发实例廊坊快速排名优化
  • phpcms网站后台模板上海个人网站建
  • 辛集专业网站建设网页设计代码免费
  • 华久做网站网站建设评审会简报
  • 郑州做网站推广的公司网站建设步骤电脑