需求
有两个SDK版本,A版本类Base有setScalingMode函数,B版本类Base无setScalingMode函数, 为了同时兼容两个SDK版本,共用一套代码,常见的是通过宏隔离,但版本众多时管理起来会很麻烦,若可先判断是否含有该函数,若有则调用,C++11新增特性解决了这一问题
//伪代码
// 如果支持setScalingMode
if(hassetScalingMode())
{
//do something
setScalingMode()
}
基本知识
SFINAE:Substitution Failure Is Not An Error
匹配失败不是错误。就是说,匹配重载的函数 / 类时如果匹配后会引发编译错误,这个函数 / 类就不会作为候选(不会报错)。这是一个 C++11 的新特性,也是 enable_if 最核心的原理,其作用是当我们在进行模板特化的时候,会去选择那个正确的模板
decltype 求表达式的类型
推导表达式的类型,但不会执行表达式
int i;
double t;
struct A { double x; };
const A* a = new A();
decltype(a) x1; //x1 是 A*
decltype(i) x2; //x2 是 int
decltype(a -> x) x3; // x3 是 double
std::declval 返回一个类型的右值引用
不管是否有默认构造函数或该类型不可以创建对象。(可以用于抽象基类);
判断是否含有某个函数
template<typename T>
bool CkHasSetScalingMode(decltype(std::declval<T>().setScalingMode(std::declval<int>())) *test = nullptr)
{
return true;
}
template<typename T>
bool CkHasSetScalingMode(...)
{
return false;
}
调用方式
CkHasSetScalingMode<className>(nullptr)
或
template<typename T>struct hasSet
{
private:
template<typename U> static auto Check(int) -> decltype(std::declval<U>().setScalingMode(std::declval<int>()), std::true_type());
template<typename U> static auto Check(...) -> decltype(std::false_type());
public:
static const bool value = std::is_same<decltype(Check<T>(0)), std::true_type>::value;
};
使用方式
hasSet<className>::value
函数存在则执行
template<typename T>
int b2hGbp(...) {
cout << "not support setScalingMode" << endl;
return -1;
};
template <typename T, void (T::*)(int mode) = &T::setScalingMode>
int b2hGbp(T *t, int mode) {
t->setScalingMode(mode);
return 0;
};
//该方案需先识别是含有该函数
/*template<typename T>
int b2hGbp(typename std::enable_if<hasSet<T>::value, T>::type *t, int mode) {
cout << "b2hGbp 2.---------------------" << endl;
t->setScalingMode(mode);
return 0;
};*/
std::enable_if
定义如下,只有第一个参数为true时才会定义type,enable_if<true, T>::type
即为 T
,而 enable_if<false, T>::type
会引发编译错误
// Primary template.
/// Define a member typedef @c type only if a boolean constant is true.
template<bool, typename _Tp = void>
struct enable_if
{ };
// Partial specialization for true.
template<typename _Tp>
struct enable_if<true, _Tp>
{ typedef _Tp type; };
参考文档:
https://blog.csdn.net/zhx6044/article/details/47295327
SFINAE https://blog.csdn.net/zjq2008wd/article/details/58180334
https://www.jianshu.com/p/45a2410d4085
enable_if https://blog.csdn.net/jeffasd/article/details/84667090
https://ouuan.github.io/post/c-11-enable-if-%E7%9A%84%E4%BD%BF%E7%94%A8/