杂货边角(23):模板编程的SFINAE机制和enable_if使用

SFINAE

SFINAE全称:Substitution Failure is not an error.即在对模板函数调用进行实例化推导匹配时出现的无效函数将被删除,并且编译器不会报错,只有最终有一个可以匹配该次调用的实例化match即可。

在对一个函数调用进行模板推导时,编译器会尝试推导所有的候选函数(模板、重载函数、普通函数),并最终结合偏特化原则,给出一个最好的匹配结果。如果在推导的过程中,出现了无效的模板参数等情况,并不会报错,而是将该实例化函数从候选集先行删除。

struct Test {
    typedef int foo;
};

template<typename T>
void func(typename T::foo) { } //第一个模板定义

template<typename T>
void func(T) { } //第二个模板定义

int main() {
    func<Test>(10); //调用#1, 根据模板推导原则,其实也会推导func(Test )的情况,但是因为SFINAE机制,不会报错;
    func<int>(10); //调用#2, 其实编译器也会实例出int::foo,这个类型不存在,但是因为SFINAE机制,不会报错;
}

std::enable_if<>

enable_if在标准库中通过结构体模板来实现,声明如下:

template<bool condition, class T = void> struct enable_if;

Enable type if the condition is met.
The type T is enabled as member type enable_if::type if Cond is true. Otherwise, enable_if::type is not defined.This is useful to hide signatures on compile time when a particular condition is not met, since in this case, the member enable_if::type will not be defined and attempting to compile using it should fail.

如果condition满足,则会声明一个类型T,如果 condition 不满足的话,会生成一个无效的类型,此处由于 SFINAE 机制的存在,只要 call 存在一个匹配的话,就不会报错(只是简单的丢弃该函数)。

std::enable_if<>的实现机制如下代码所示:

template<bool Cond, typename T = void> struct enable_if {};

template<typename T> struct enable_if<true, T> { typedef T type; };

在 condition 为真的时候,由于偏特化机制,第二个结构体模板明显是一个更好的匹配,所以 std::enable_if<>::type就是有效的。当 condition 为假的时候,只有第一个结构体模板能够匹配,所以 std::enable_if<>::type 是无效的,会被丢弃,也不会因为enable_if的使用导致报错。

可以根据C++官网的enable_if使用demo来观看使用方式

// enable_if example: two ways of using enable_if
#include <iostream>
#include <type_traits>

// 1. the return type (bool) is only valid if T is an integral type:
//将enable_if用在返回值的类型定义上,可以参考返回值类型追踪机制,异曲同工,不过这里只有在T是int时,返回值才
//是bool,否则实例化的函数无效
template <class T>
typename std::enable_if<std::is_integral<T>::value,bool>::type
  is_odd (T i) {return bool(i%2);}

// 2. the second template argument is only valid if T is an integral type:
template < class T,
           class = typename std::enable_if<std::is_integral<T>::value>::type>
bool is_even (T i) {return !bool(i%2);}

int main() {

  short int i = 1;    // code does not compile if type of i is not integral

  std::cout << std::boolalpha;
  std::cout << "i is odd: " << is_odd(i) << std::endl;
  std::cout << "i is even: " << is_even(i) << std::endl;

  return 0;
}

OUTPUT

i is odd: true
i is even: false
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值