ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

c++模板day4

2022-05-03 13:34:26  阅读:133  来源: 互联网

标签:const template max day4 c++ && auto 模板


  1 太懒了,发现一个博主写得非常好,原文来源https://www.cnblogs.com/zhangyachen/p/13946442.html
  2 这里我是copy了一些我认为比较重要的
  3 
  4 模板的编译和链接问题
  5 
  6 大多数人会按照如下方式组织非模板代码:
  7 
  8 将类或者其他类型声明放在头文件(.hpp、.H、.h、.hh、.hxx)中。
  9 将函数定义等放到一个单独的编译单元文件中(.cpp、.C、.c、.cc、.cxx)。
 10 但是这种组织方式在包含模板的代码中却行不通,例如:
 11 
 12 头文件:
 13 // myfirst.hpp
 14 #ifndef MYFIRST_HPP
 15 #define MYFIRST_HPP
 16 // declaration of template
 17 template<typename T>
 18 void printTypeof (T const&);
 19 #endif // MYFIRST_HPP
 20 
 21 定义函数模板的文件:
 22 
 23 // myfirst.cpp
 24 #include <iostream>
 25 #include <typeinfo>
 26 #include "myfirst.hpp"
 27 // implementation/definition of template
 28 template<typename T>
 29 void printTypeof (T const& x) {
 30   std::cout << typeid(x).name() << '\n';
 31 }
 32 
 33 在另一个文件中使用该模板:
 34 
 35 // myfirstmain.cpp
 36 #include "myfirst.hpp"
 37 // use of the template
 38 int main() {
 39   double ice = 3.0;
 40   printTypeof(ice); // call function template for type double
 41 }
 42 在c/c++中,当编译阶段发现一个符号(printTypeof)没有定义只有声明时,编译器会假设它的定义在其他文件中,所以编译器会留一个”坑“给链接器linker,让它去填充真正的符号地址。
 43 
 44 但是上面说过,模板是比较特殊的,需要在编译阶段进行instantiation,即需要进行模板参数类型推断,实例化模板,当然也就需要知道函数的定义。但是由于上面两个cpp文件都是单独的编译单元文件,所以当编译器编译myfirstmain.cpp时,它没有找到模板的定义,自然也就没有instantiation。
 45 
 46 解决办法就是我们把模板的声明和定义都放在一个头文件。大家可以看一下自己环境下的vector等STL源文件,就是把类的声明和定义都放在了一个文件中。
 47 
 48 普通函数可以在头文件声明,cpp上定义,其他文件调用该函数此时可以通过链接阶段找到该函数的定义;
 49 而模板需要在编译过程中就需要找到定义。
 50 
 51 
 52 在C++11中,我们可以利用auto和trailing return type来让编译器找出返回值类型:
 53 
 54 template <typename T1, typename T2>
 55 auto max(T1 a, T2 b) -> decltype(b < a ? a : b) {
 56   return b < a ? a : b;
 57 }
 58 
 59 在C++14中,我们可以省略trailing return type:
 60 
 61 template<typename T1, typename T2>
 62 auto max (T1 a, T2 b) {
 63     return b < a ? a : b;
 64 }
 65 
 66 重载函数模板
 67 这个跟普通函数重载也类似:
 68 
 69 // maximum of two int values:
 70 int max(int a, int b) { 
 71   return b < a ? a : b; 
 72 }
 73 
 74 // maximum of two values of any type:
 75 template <typename T> 
 76 T max(T a, T b) { 
 77   return b < a ? a : b; 
 78 }
 79 
 80 int main() {
 81   max(7, 42);         // calls the nontemplate for two ints
 82   max(7.0, 42.0);     // calls max<double> (by argument deduction)
 83   max('a', 'b');      // calls max<char> (by argument deduction)
 84   max<>(7, 42);       // calls max<int> (by argument deduction)
 85   max<double>(7, 42); // calls max<double> (no argument deduction)
 86   max('a', 42.7);     // calls the nontemplate for two ints
 87 }
 88 这里需要解释下最后一个max('a', 42.7)。因为在模板参数类型推导过程中不允许类型自动转换,但是调用普通函数是允许的,所以这个会调用非模板函数 
 89 模板参数类型推导过程中不允许类型自动转换!!!
 90 
 91 
 92 重载时最好不要随便改变模板参数个数,最好可以显示的指定模板参数类型
 93 下面是段有问题的代码:
 94 
 95 // maximum of two values of any type (call-by-reference)
 96 template <typename T> T const &max(T const &a, T const &b) {
 97   return b < a ? a : b;
 98 }
 99 
100 // maximum of two C-strings (call-by-value)
101 char const *max(char const *a, char const *b) {
102   return std::strcmp(b, a) < 0 ? a : b;
103 }
104 
105 // maximum of three values of any type (call-by-reference)
106 template <typename T> T const &max(T const &a, T const &b, T const &c) {
107   return max(max(a, b), c);           // error if max(a,b) uses call-by-value
108 }
109 
110 int main() {
111   auto m1 = max(7, 42, 68);         // OK
112 
113   char const *s1 = "frederic";
114   char const *s2 = "anica";
115   char const *s3 = "lucas";
116   auto m2 = max(s1, s2, s3);         // run-time ERROR
117 }
118 问题出现在return max (max(a,b), c);,因为char const *max(char const *a, char const *b)的参数是按值传递,max(a,b)会产生一个指向已经销毁的栈帧地址,这会导致未定义行为。
119 如果不拿个中间变量保存函数返回值,那么它就会消亡了,在调用Max(消亡值,s3)产生错误;
120 
121 
122 
123 引子
124 T&&在代码里并不总是右值引用:
125 
126 void f(Widget&& param);      // rvalue reference
127 
128 Widget&& var1 = Widget();      // rvalue reference
129 
130 auto&& var2 = var1;        // not rvalue reference
131 
132 
133 template<typename T>
134 void f(std::vector<T>&& param);      // rvalue reference
135 
136 
137 template<typename T>
138 void f(T&& param);     // not rvalue reference
139 T&&代表两种含义:
140 
141 右值引用
142 万能引用(universal references, or forwarding references)
143 如何区分
144 万能引用一般出现在两个场景中:(万能引用可以推断是左值引用还是右值引用,泛型接口) 
145 
146 1.模板参数
147 template<typename T>
148 void f(T&& param); // param is a universal reference
149 2.auto声明
150 auto&& var2 = var1; // var2 is a universal reference
151 
152 总结:万能引用只存在于推理类型,而右值引用是确定类型 
153 
154 auto声明
155 对于auto的场景来说,所有的auto&&都是万能引用,因为它总是有参数推导的过程。例如定义一个记录函数执行时间的lambda(C++14中允许使用auto来声明lambda的函数):
156 
157 auto timeFuncInvocation = [](auto &&func, auto &&... params) {  
158   start timer;
159   std::forward<decltype(func)>(func)(                      // invoke func
160       std::forward<decltype(params)>(params)...      // on params
161   );
162   stop timer and record elapsed time;
163 };
164  

 

标签:const,template,max,day4,c++,&&,auto,模板
来源: https://www.cnblogs.com/matt-su/p/16218158.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有