C++ SFINAE和 enable_if

本文介绍了C++中的SFINAE原则,即模板替换失败不是错误,以及如何利用enable_if进行条件编译。通过示例展示了这两个概念如何协同工作,实现模板函数的选择和类型检查。同时提到了类型萃取(typetraits)在其中的作用,并给出了使用enable_if结合std::is_integral实现类型检查的模板函数例子。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

c++中的SFINAE和enable_if,如果经常写模板的话,应该听到看到这些东西.

SFINAE

首先介绍下SFINAE,参考官方介绍,中文是“模板替换失败不是一种错误”,看个代码示例

class Test {
	using newType = int;
};
// 1
template<typename T> 
void f(T arg) {
	cout<<"old  type"<<endl;
}
// 2
template <typename T>
void f(T::newType arg) {
	cout<<"new type"<<endl;
}
f<int>(10);  // 输出 old type
f<Test>(10); // 输出new type

这里,当将函数 f 用int类型实例化后,他可以匹配第一个函数模板,但无法匹配第二个函数模板,因为int内部没有一个叫newType的类型,int::newType是不合法的,但是这里不会报错,这其实就是SFINAE的核心。虽然第二个模板匹配失败了,但他可以匹配第一个模板函数,所以模板替换失败了不是一种错误,会让编译器去寻找下一个匹配的模板,这里的f<Test>,两个都可以匹配,但第二个模板匹配的更加具体,所以优先级高于第一个。
SFINAE要配合enable_if的,才能显示效果,下面说说 enable_if.

enable_if

enable_if是c++标准库实现的,内部实现类似于这样:

// 1
template<bool U, class T = void>
struct enable_if {};
 
 // 2
template<class T>
struct enable_if<true, T> { using type = T; };

第二个结构体模板,其实就是第一个的偏特化版本,对第一个模板参数为true的时候做了一种偏特化。
举个使用实例:

typename std::enable_if<true, int>::type t; //编译通过, t是int类型

typename std::enable_if<false, int>::type t2; //编译失败,因为struct enable_if中没有type类型

这里其实还有一点type traits的概念,中文叫 “类型萃取”,这个在c++模板元编程中,以及c++ 的STL中,都是非常常见的用法,这里不再介绍了。
从上面的实例可以看到,如果第一个模板参数是bool, 那么编译可以成功,如果false,编译就是失败了,联合SFINANE,就可以做很多了,比如:

// std:;is_inergral
template <typename T>
typename std::enable_if<std::is_integral<T>::value>::type test(T value)
{
    std::cout<<"T is int"<<std::endl;
}

// 注意 这里是 !std::is_intergral, 是 非
template <typename T>
typename std::enable_if<!std::is_integral<T>::value>::type test(T value)
{
    std::cout<<"T is not int"<<std::endl;
}
test("abc"); // 输出 T is not int
test(1);	// 输出T is int

因为"abc"是字符串,但是第一个模板函数要求是int, 所以enable_if的第一个模板参数是false, 那么就导致enable_if中没有type类型,导致编译不过,但由于SFINAE机制,不会报错,所以去寻找下一个可匹配的模板函数。

SFINAE,enable_if在模板中很常见,是元编程的基础技术。这里抛出引玉 :)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值