1.windows能编译过、linux不能编译通过的问题
1.1 模板特例化
1.1.1 问题描述:
如下代码
using namespace std;
class temp1{
public:
int32_t nums;
};
class A {
public:
template<typename T1>
int32_t getNums(T1 t1) { return t1.nums; }
template<>
int32_t getNums(std::string str) {
int32_t res = std::stoi(str);
return res;
}
};
在windows上能通过编译,在linux上没有通过编译,编译报错在template<>的“>”这个位置
1.1.2 解决办法
1.1.2.1 第一种,该特例化为重载
修改代码为:
using namespace std;
class temp1{
public:
int32_t nums;
};
class A {
public:
template<typename T1>
int32_t getNums(T1 t1) { return t1.nums; }
int32_t getNums(std::string str) {
int32_t res = std::stoi(str);
return res;
}
};
取消特例化模板,改为重载
1.1.2.2 第二种,增加模板参数判断
1.1.2.1中所述方法,能编译成功,但是在执行时,可能会存在,比如传入std::string类型的数据,我们期望他走重载的方法,但是实际上他还是走的模板方法。
这时因为C++ 中的模板方法会优先于重载方法,尤其是在模板参数可以匹配的情况下。这种情况可以增加模板参数判断。
代码如下:
using namespace std;
class temp1{
public:
int32_t nums;
};
class A {
public:
template<typename T1, typename = typename std::enable_if_t<
!std::is_same_v<T1,std::string>>
int32_t getNums(T1 t1) { return t1.nums; }
int32_t getNums(std::string str) {
int32_t res = std::stoi(str);
return res;
}
};
有可能有些不支持c++17新特性,可以改用c++14特性
using namespace std;
class temp1{
public:
int32_t nums;
};
class A {
public:
template<typename T1, typename = typename std::enable_if<
!std::is_same<T1,std::string>::value>::type>
int32_t getNums(T1 t1) { return t1.nums; }
int32_t getNums(std::string str) {
int32_t res = std::stoi(str);
return res;
}
};
1.1.3 报错原因分析
windows上支持类中的模板函数特例化,但是linux上不支持类中的模板函数特例化。
1.1.4 延展
如下代码:
template<typename T1>
int32_t getNums(T1 t1) { return t1.nums; }
template<>
int32_t getNums(std::string str) {
int32_t res = std::stoi(str);
return res;
}
这样的模板函数,windows和linux环境都能支持。
总结:
- 类模板函数,linux不支持特例化
- 普通模板函数,windows和linux都能支持特例化
linux环境能不能特例化模板类,没有验证过。
1.1.5 其他可能出现的问题
如果模板方法,有两个入参,第一个参数是模板参数,第二参数带有默认参数,如下:
using namespace std;
class temp1{
public:
int32_t nums=1024;
};
class temp2{
public:
int32_t nums=0;
};
class A {
public:
// 类模板方法
template<typename T1>
int32_t getNums(T1 t1,int32_t index = 0) {
return t1.nums;
}
// 重载方法
int32_t getNums(temp2 t2,int32_t index) {
return t2.nums;
}
};
如果在测试时
A a;
temp2 t2;
a.getNums(t2);
这时走的是类模板方法,而不是重载方法,因为没有传index的参数,只有类模板方法有默认的index入参。
如果想要调用重载方法,
那么需要传入index参数,这个没验证
a.getNums(t2,0);
或者给重载方法一个默认入参,重载方法修改为(这个验证过):
// 重载方法
int32_t getNums(temp2 t2,int32_t index = 0) {
return t2.nums;
}
这时编码时的疏忽造成的,因此为了保险起见,推荐1.1.2.2提供的方式,增加模板参数判断,这样不匹配时,就没有合适的方法被执行,方便排查问题。