C++ traits和enable_if的实现

本文介绍了C++ traits的概念及其应用,通过实例展示了如何使用traits来控制模板函数的行为,确保只有特定类型的参数才能被接受。

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

C++ traits中的trait在中文里好像没有特别好的翻译。引用C++之父Bjarne Stroustrup的话来解释什么是C++ traits:

"Think of a trait as a small object whose main purpose is to carry information used by another object or algorithm to determine "policy" or "implementation details."

翻译过来就是:trait是一个很小的对象。它的主要作用是携带信息,以便其他的对象或者算法可以使用它来确定策略或者实现细节。

这么说起来还是不太好理解,举个例子大概会明白一些。我们构造一个trait叫做is_int_long:

template <typename T>
struct is_long_or_int {
    static const bool value = false;
};

template <>
struct is_long_or_int<int> {
    static const bool value = true;
};

template <>
struct is_long_or_int<long> {
    static const bool value = true;
};

上面定义了一个模板类,叫做is_long_or_int<T>(如果这时候你在想这个定义的是一个结构而不是一个类,建议你去复习一下C++,弄清楚class和struct两个关键字的区别)。这个模板类里面有个静态的常量value,它的值是false。然后我们将这个模板类特殊化了两次,分别使得模板参数为int或者long的时候那个静态常量value的值为true,也就是:

is_long_or_int<int>::value == true;
is_long_or_int<long>::value == true;
is_long_or_int<T>::value == false; //其他所有的类型
这个模板类is_long_or_int就是一个trait,它携带了给定类T是否是int或者long的信息。

这看起来很无聊,又有什么用呢?其实用处很大。例如我有一个模板函数:

template <typename T>
bool larger_than_five(T a) {
    return a > (T)5;
}
这是一个很简单的函数,只是为了用来为解释trait的作用服务,请不要纠结其中实现的细节。这个函数中用了大于运算符(>),并且和5来比较,并不是所有的这样的比较都有意义。比如说:

void *p = NULL;
larger_than_five(p); //毫无意义
不但毫无意义,更可能是一个编程的错误。最好的解决办法是:只允许使用int和long来实例化这个模板函数,而不允许其他任何类型。当然可以是unsigned int或者unsigned long,为了简洁,我们这里只允许int和long。可是,C++的核心语言标准中并没有提供这样的语法。然而,使用C++ trait就能很好的解决这个问题。

C++11标准库中有个模板类叫做enable_if,正是用来实现这种功能的。我们只需要把上述模板函数larger_than_five改写成如下这个样子:

template <typename T>
typename enable_if<larger_than_five<T>::value, bool>::type
larger_than_five(T a) {
    return a > (T)5;
}

如果看上去很复杂,不用着急,容我来一点点地解释。首先,要了解enable_if的实现,大概是如下这个样子,当然模板库里面的会有很多不同:

template <bool b, typename T>
struct enable_if {
};

template <typename T>
struct enable_if<true, T> {
    typedef T type;
};
我们可以看到enable_if其实是个模板类,当且仅当它的第一个参数的值为true的时候,在类中typedef定义一个type的类,类型与T相同。看完了这个,我们在看上面那个larger_than_five的模板函数。其中,enable_if中的b = larger_than_five<T>::value。如果T = int 或者long,larger_than_five<T>::value的值是true,那么enable_if中的type就定义为T,所以larger_than_five模板函数就等价为:

template <typename T>
bool 
larger_than_five(T a) {
    return a > (T)5;
}
和我们看到它的第一个版本一模一样!如果我们给的类型不是int或者long,比如说void *,那么enable_if中就没有type这个定义,所以larger_than_five这个模板函数就变成了:

template <typename T> 
larger_than_five(T a) {
    return a > (T)5;
}

编译器就会给出error,程序便无法编译。


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值