六安品牌网站建设怎么样,网站建设及制作,免费有趣的网站,wordpress在线教育系统类型推断 模板在编译过程中#xff0c;会进行类型推断#xff0c;平时使用到隐式类型转换#xff08;自动类型转换#xff09;#xff0c;在类型推断时#xff0c;几乎全部失效。经常用到的隐式类型转换包含以下几种#xff1a;
从低精度类型到高精度类型的转换#x…类型推断 模板在编译过程中会进行类型推断平时使用到隐式类型转换自动类型转换在类型推断时几乎全部失效。经常用到的隐式类型转换包含以下几种
从低精度类型到高精度类型的转换如char-intint-double从数组到指针如char []-char *通过构造函数进行类型转换例如char *-std::stringstd::string str hello通过继承关系子类对象引用自动转成基类对象引用如B派生自A对于函数A max5(A x, A y), 定义对象 A a和对象B bmax(a, b)这样的调用是没有问题的 下面是一段测试代码
#include cstdio
#include stringtemplate typename T
T max1(T x, T y)
{printf(x : %s, y : %s\n, typeid(x).name(), typeid(y).name());return x y ? x : y;
}template typename T
T max2(T x, T y)
{printf(x : %s, y : %s\n, typeid(x).name(), typeid(y).name());return x y ? x : y;
}template typename T
const T max3(const T x, const T y)
{printf(x : %s, y : %s\n, typeid(x).name(), typeid(y).name());return x y ? x : y;
}class A
{
public:A(int i) : m_data(i) {}bool operator (const A rhs) const {printf(A\n);return m_data rhs.m_data;}protected:int m_data;
};class B : public A
{
public:B(int i) : A(i) {}bool operator (const B rhs) const {printf(B\n);return m_data rhs.m_data;}};int main(int argc, char **argv)
{char c0 a;int i0 10;int *i0p i0;const int i1 14;double d0 3.14;char *s0 100;char s1[8] hello;const char *s2 world;std::string str0 200;A a0(10);B b0(12);A a1 a1;A a2 b0;max1(c0, i0); //Candidate template ignored: deduced conflicting types for parameter T (char vs. int)max1(i0, d0); //Candidate template ignored: deduced conflicting types for parameter T (int vs. double)max1(i0, i1); //int max1(int, int) 无法确认是否有const修饰符max1(s0, s1); //char *max1(char *, char *)max1(s0, str0); //Candidate template ignored: deduced conflicting types for parameter T (char * vs. std::string (aka basic_stringchar))max1(s0, s2); //Candidate template ignored: deduced conflicting types for parameter T (char * vs. const char *)max1(a0, b0); //Candidate template ignored: deduced conflicting types for parameter T (A vs. B)max1(a1, a2); //A max1(A, A)max1(a0, a2); //A max1(A, A)max1(a0, b0); //Candidate template ignored: deduced conflicting types for parameter T (A vs. B)max2(c0, i0); //Candidate template ignored: deduced conflicting types for parameter T (char vs. int)max2(i0, d0); //Candidate template ignored: deduced conflicting types for parameter T (int vs. double)max2(i0, i1); //Candidate template ignored: deduced conflicting types for parameter T (int vs. const int)max2(i0, i1); //Candidate template ignored: deduced conflicting types for parameter T (int vs. const int)max2(s0, s1); //Candidate template ignored: deduced conflicting types for parameter T (char * vs. char[8])max2(s0, str0); //Candidate template ignored: deduced conflicting types for parameter T (char * vs. std::string (aka basic_stringchar))max2(s0, s2); //Candidate template ignored: deduced conflicting types for parameter T (char * vs. const char *)max2(a0, b0); //Candidate template ignored: deduced conflicting types for parameter T (A vs. B)max2(a1, a2); //A max2(A, A)max2(a0, a2); //A max2(A, A)max2(a0, b0); //Candidate template ignored: deduced conflicting types for parameter T (A vs. B)max3(c0, i0); //Candidate template ignored: deduced conflicting types for parameter T (char vs. int)max3(i0, d0); //Candidate template ignored: deduced conflicting types for parameter T (int vs. double)max3(i0, i1); //int max3(int, int) 无法确认是否有const修饰符max3(s0, s1); //Candidate template ignored: deduced conflicting types for parameter T (char * vs. char[8])max3(s0, str0); //Candidate template ignored: deduced conflicting types for parameter T (char * vs. std::string (aka basic_stringchar))max3(s0, s2); //Candidate template ignored: deduced conflicting types for parameter T (char * vs. const char *)max3(a0, b0); //Candidate template ignored: deduced conflicting types for parameter T (A vs. B)max3(a1, a2); //A max3(A, A)max3(a0, a2); //A max3(A, A)max3(a0, b0); //Candidate template ignored: deduced conflicting types for parameter T (A vs. B)}通过上面的代码可以看出模板使用非const引用传参是对变量类型要求最严格的不允许任何隐式类型转换模板使用const引用传参允许const类型和非const类型转换模板使用值传参支持数组到同类型指针的转换也支持const类型和非const类型的转换。关于const类型和非const类型转换从代码看不出到底是const类型转换成了非const类型还是非const类型转换成了const类型但可以从最终的二进制文件看出max1是把const int转换成了intmax3是吧int转换成了const int如下 如果确实要使用到不同的类型有3中处理方案
强制类型转换
max1(static_castdouble(3), 3.14);
显示指出T的类型告诉编译器不做类型推导
max1double(3, 3.14);
使用多个模板参数指明参数类型有可能不相同
多模板参数 多模板参数很好理解但在某些情况下如上文中的max函数面临一个问题——如何选择返回值类型为什么这个问题很重要先来看一个例子如下
#include cstdiotemplate typename T1, typename T2
T1 max1(T1 x, T2 y)
{return x y ? x : y;
}int main(int argc, char **argv)
{auto temp1 max1(4.14, 3); //temp1 4.14auto temp2 max1(3, 4.14); //temp2 4return 0;
} 看到这样的结果是不是感到很困惑为什么会有这样的结果从max1的定义可以看出max1返回值的类型是第一个参数的类型。尽管两次调用的参数都是4.14和3但第一次调用返回值类型T1和4.4相同为double所以返回值为4.14第二次调用返回值类型T1和3相同为int尽管计算结果和第一次相同为4.14但返回时被转换int类型变为4. 基于上面的问题必须认真对待返回值的类型。关于上述问题有三种解决方案
专门为返回值声明一个模板类型
#include cstdiotemplate typename T1, typename T2, typename RT
RT max2(T1 x, T2 y) {return x y ? x : y;
}int main(int argc, char **argv)
{auto temp1 max2(4.14, 3); //temp1 4.14auto temp2 max2(3, 4.14); //temp2 4return 0;
} 上面的源码就可以运行了吗(⊙o⊙)…编译失败了
Candidate template ignored: couldnt infer template argument RT
Candidate template ignored: couldnt infer template argument RT 原因是编译器仅对函数参数的类型进行推导RT不是任何参数的类型所以不会被推导。必须使用下面的方法调用 auto temp1 max2double, int, double(4.14, 3);auto temp2 max2int, double, double(3, 4.14); 是不是很繁琐一个不小心又会翻船
返回值类型声明为auto让编译器推导返回类型
#include cstdiotemplate typename T1, typename T2
auto max3(T1 x, T2 y) {return x y ? x : y;
}int main(int argc, char **argv)
{auto temp1 max3(4.14, 3);auto temp2 max3(3, 4.14);return 0;
} 上述测试代码仅对c14及以后版本生效。对于c11上述源码会报错 error: auto return without trailing return type; deduced return types are a C14 extension 关于上述错误可以使用decltype关键字对返回类型进行显示推导
template typename T1, typename T2
auto max4(T1 x, T2 y) - decltype(true ? x : y) {return x y ? x : y;
} 注意decltype操作符仅仅推导传入语句运算结果的的类型不关心最终结果因此还可以如下实现
template typename T1, typename T2
auto max4(T1 x, T2 y) - decltype(x - y) {return x y ? x : y;
} 再换种实现看下是不是很想lambda表达式
template typename T1, typename T2
auto max4(T1 x, T2 y) - double {return x y ? x : y;
} 将返回值设置为公共类型
template typename T1, typename T2
std::common_type_tT1 , T2 max5(T1 x, T2 y) {return x y ? x : y;
} 注意此时声明中不能出现任何引用的痕迹std::common_type_tT1 , T2 max5(T1 x, T2 y) 或std::common_type_tT1 , T2 max5(T1 x, T2 y)都是错误的方式。
Candidate function [with T1 double, T2 int] not viable: expects an lvalue for 1st argument 对于c11common_type_t的使用方式和此处有点不一样下面是c11的实现
template typename T1, typename T2
typename std::common_typeT1 , T2::type max6(T1 x, T2 y) {return x y ? x : y;
} 默认模板参数 标题中的概念很好理解就是给模板参数指定一个默认值。对于模板参数的默认值是直接指定还是通过计算推导得出编译器是不关心的因此下面几种实现都是可以的
#include cstdio
#include type_traitstemplate typename T1, typename T2, typename RTdouble
RT max1(T1 x, T2 y) {return x y ? x : y;
}template typename T1, typename T2, typename RTstd::decay_tdecltype(true ? T1() : T2())
RT max2(T1 x, T2 y) {return x y ? x : y;
}template typename T1, typename T2, typename RTstd::common_type_tT1, T2
RT max3(T1 x, T2 y) {return x y ? x : y;
}int main(int argc, char **argv)
{auto v1 max1(7.98, 10);auto v2 max2(7.98, 10);auto v3 max3(7.98, 10);return 0;
}模板函数重载 模板函数重载比普通函数重载更为复杂模板参数的个数不同也可以算作重载即使其中的某些模板参数不使用。但是不要试图通过不同的模板参数名称去实现模板函数的重载这样只会有两种可能重复的函数定义模板实例不知道调用哪个实现。 一个非模板函数可以和一个与其同名的函数模板共存并且这个同名的函数模板可以被实例化为与非模板函数具有相同类型的调用参数。在所有其它因素都相同的情况 下模板解析过程将优先选择非模板函数而不是从模板实例化出来的函数。下面是测试代码
#include cstdio
#include cstringtemplate typename T
T max1(T x, T y) {return x y ? x : y;
}// Redefinition of max1
/*template typename U
U max1(U x, U y) {return x y ? x : y;
}*/template typename T, typename RT
T max1(T x, T y) {return x y ? x : y;
}template typename T1, typename T2, typename RTdecltype(true ? T1() : T2())
RT max1(T1 x, T2 y) {return x y ? x : y;
}//如果存在下面的定义m1将会不知道调用RT max1(T2 x, T1 y)还是RT max1(T1 x, T2 y)
/*template typename T1, typename T2, typename RTdecltype(true ? T1() : T2())
RT max1(T2 x, T1 y) {return x y ? x : y;
}*///template打开此处注释m6会调用该函数
const char *max1(const char *s1, const char *s2) {return strcmp(s1, s2) 0 ? s1 : s2;
}int main(int argc, char **argv)
{auto m1 max1(100, 4.8); //RT max1(T1 x, T2 y)auto m2 max1(abc, efd); //const char *max1(const char *s1, const char *s2)//auto m3 max1(abc, 10000); //Candidate template ignored: substitution failure [with T1 const char *, T2 int]: incompatible operand types (const char * and int)auto m4 max1(10, 245); //T max1(T x, T y)auto m5 max1int, int(10, 245); //template typename T, typename RT T max1(T x, T y)auto m6 max1(abc, efd); //T max1(T x, T y)强制使用模板函数return 0;
}