C++标准库的的编写方法是基于模板元来编程的,既然是用模板,那么就少不了与类型打交道,而C++11标准库中新加入了<type_traits>
头文件,这个里面新加入了很多与类型特性有关的模板元,在编译期间这些东西就是利器,非常好用。
而打开<type_traits>
头文件,看到的第一个模板类就是integral_constant
,这个类是type_traits
的基石,基本上type_traits
都直接或间接继承自integral_constant
,而且,C++标准库中还有很多模板类也是继承了integral_constant
,例如std::ratio
。
integral_constant
的意思是积分常量,这是我Google 回来的意思,其实,这个类就是提供了一个编译期常量。
先来看看源码:
/// integral_constant
template<typename _Tp, _Tp __v>
struct integral_constant
{
static constexpr _Tp value = __v;
typedef _Tp value_type;
typedef integral_constant<_Tp, __v> type;
constexpr operator value_type() const
{
return value;
}
#if __cplusplus > 201103L
#define __cpp_lib_integral_constant_callable 201304
constexpr value_type operator()() const
{
return value;
}
#endif
};
template<typename _Tp, _Tp __v>
constexpr _Tp integral_constant<_Tp, __v>::value;
可以看到,integral_constant
只有一个静态常量表达式变量value
,由于是静态变量,因此要在类外声明;
然后就是两个typedef
,这是traits
的老套路了,喜欢在类中重定义一些类型,说白了就是把别人东西的包一层,然后作为一个中间层告诉用户需要的东西;
接着就是两个操作符重载了。
在C++14中重载了函数运算符,这非常有用,假设现在你需要写一个函数,这个函数返回App的版本号,这个版本号是个常量,不会变(假设啊),你肯定会这么写:
#define APP_VERSION 20181010L
const char * GetAppVersion() { return APP_VERSION; }
那么在C++14中,你可以这么写:
struct GetAppVersion : public std::integral_constant<unsigned int, APP_VERSION> {};
然后像函数一样调用就行了,auto appVersionString = GetAppVersion()
,非常好用。因此,凡是需要返回一些常量的函数都可以这么写。
到这里,源码就分析完了,是不是特别简单,但是,这东西有什么用呢?貌似还没有说清楚。
先来看看三个特别重要的东西:
/// The type used as a compile-time boolean with true value.
typedef integral_constant<bool, true> true_type;
/// The type used as a compile-time boolean with false value.
typedef integral_constant<bool, false> false_type;
template<bool __v>
using __bool_constant = integral_constant<bool, __v>;
前两个是不是好熟悉啊,看《STL源码剖析》,SGI有一个__type_traits
也有__true_type
和__false_type
,从前面的两条下划线可以知道,当时的__type_traits
只能供内部使用,并不是C++标准规范之中的内容,然后再来看看当时的这两个类型是如何定义的:
struct __true_type {};
struct __false_type {};
把这两个定义和C++11中的两个定义比较一下,你就会发现,C++11的true_type / false_type
是多么有血有肉,调用std::true_type::value
还可以得到true
。
这也是为什么我之前说type_traits
中的大部分类都直接或间接继承自integral_constant
,你可以继续看看type_traits
中其他类,凡是带前缀is_*
的类的偏特化或特化都是继承自true_type
。例如下面的__is_pointer_helper
:
template<typename>
struct __is_pointer_helper : public false_type { };
template<typename _Tp>
struct __is_pointer_helper<_Tp*> : public true_type { };
这种例子在type_traits
中比比皆是。
__bool_constant
这是一个辅助类型重定义,可以用在模板函数重载中。
integral_constant
的另一作用就是用在std::ratio
编译器分数类中,这个在另一篇博客会有介绍。
目前解除到的关于integral_constant
就这么多,以后有机会再完善。