本文已参与「新人创作礼」活动,一起开启掘金创作之路。
模板偏特化
在正式介绍类型萃取技术之前,还是简单的略过一下模板偏特化
对于一个模板来说,特化分为全特化和偏特化
在模板进行匹配时 会选择最合适的一个进行实例化
template <typename T, typename V> struct E {
E() { cout << "默认\n"; }
};
template <> struct E<int, int> {
E() { cout << "全特化\n"; }
};
template <typename T> struct E<T, int> {
E() { cout << "偏特化\n"; }
};
利用函数偏特化搞事情
总所周知,现在C++20才有的concept ,在没有这个东西之前,我们的模板是非常不安全的
我们可以用一些东西来进行模板约束,那就是模板偏特化来约束
template <typename T, bool v> struct bool_ {
static constexpr bool ret = v;
using value_type = T;
operator bool() { return ret; }
};
using false_ = bool_<bool, false>;
using true_ = bool_<bool, true>;
template <bool v, typename VALUE> struct if_ {};
template <typename TRUE> struct if_<true, TRUE> { using value_type = TRUE; };
template <typename T> struct isIntegral : bool_<T, false> {};
template <> struct isIntegral<float> : bool_<float, true> {};
template <> struct isIntegral<double> : bool_<double, true> {};
template <> struct isIntegral<int> : bool_<int, true> {};
template <> struct isIntegral<long> : bool_<long, true> {};
template <> struct isIntegral<long long> : bool_<long long, true> {};
template <typename T>
auto add(T a, T b) -> typename if_<isIntegral<T>::ret, T>::value_type {
return a + b;
}
int main() {
cout << add(1, 2); // ok
cout << add("11", "22"); // 编译失败
return 0;
}
是不是有点熟悉?
这不就是stl中的enable_if的套路吗
没错,就是这个样子
类型萃取
进入正题,C++中有了模板,有了模板偏特化,我们可以干很多事情
比如,类型萃取,说白了,就是根据最合适的,进行萃取它的所有属性
比如
using namespace std;
template <typename T> struct remove_const_v { using type = T; };
template <typename T> struct remove_const_v<const T> { using type = T; };
template <typename T> struct remove_const_v<T *> { using type = T; };
template <typename T> struct remove_const_v<const T *> { using type = T; };
template <typename T> struct traits_v {
using value_type = typename remove_const_v<T>::type;
};
int main() {
{
traits_v<int>::value_type x;
cout << typeid(x).name() << endl;
}
{
traits_v<int *>::value_type x;
cout << typeid(x).name() << endl;
}
{
traits_v<const int>::value_type x;
cout << typeid(x).name() << endl;
}
{
traits_v<const int *>::value_type x;
cout << typeid(x).name() << endl;
}
return 0;
}
上述例子利用模板特性把T的真正值类型给萃取出来了
同样的道理,我们可以去萃取他的指针类型
比如下面这个更加全面的STL里面的迭代器的萃取类型
template<typename _Category, typename _Tp, typename _Distance = ptrdiff_t,
typename _Pointer = _Tp*, typename _Reference = _Tp&>
struct iterator {
typedef _Category iterator_category;
typedef _Tp value_type;
typedef _Distance difference_type;
typedef _Pointer pointer;
typedef _Reference reference;
};
迭代器的萃取机制的目的也是一样的,就是为了将值类型,指针类型,引用类型给萃取出来
比如我要看当前类型是不是void,c++中是这么做的
template<typename _Tp>
struct is_void
: public __is_void_helper<__remove_cv_t<_Tp>>::type
{ };
template <typename _Tp>
inline constexpr bool is_void_v = is_void<_Tp>::value;
template<typename>
struct __is_void_helper
: public false_type { };
template<>
struct __is_void_helper<void>
: public true_type { };
更多c++提供的type_traits 请看这儿 zh.cppreference.com/w/cpp/meta