有两个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/
最近工作中遇到这样一个需求:实现一个ToString函数将类型T转换到字符串,如果类型T中含有同名方法ToString则直接调用。
这样一个ToString实现可以使用std::enable_if来做到,但是这里的难点在于如何判断类型T中存在这样一个ToString方法,以便可以放入enable_if中做SFINAE。
检查类中是否存在特定成员
相同的问题在知乎上有人提出过,@孙明琦的答案提供了一个用于检测特定检测子U在类型T下是否有效的检测器is_detected_v。其中用到了一个C++17的std::void_t,考虑到目前C++17还没得用,这个实现只作参考之用(事实上C++
在C++模板中,SFINEA规则是指”Substitution failure is not an error“(匹配失败不是错误)。具体来说,就是当重载的模板参数展开时,如果展开导致一些类型不匹配,编译器并不报错。
我们可以使用这个规则来判断类是否存在某个成员函数,请看下面的实例:
#include
#include
#include
template
struct has_member_
namespace detail {
template <class Default, class AlwaysVoid, template <class...> class Op,
class... Args>
struct detector {
using value_t = std::false_type;
using type = Default;
template &
template<typename T, uint32_t (T::*)(uint32_t) const = &T::Func>
static constexpr bool Check(T *) { return true; }
static constexpr bool Check(...) { return false; }