欢迎光临散文网 会员登陆 & 注册

大忙人系列-程序猿在想什么 (四·二) C++的食用方法

2020-01-22 18:53 作者:汐留楓Channel  | 我要投稿

三. 模板是如何整活的

从一个简单的iterSwap开始,假设能交换两个迭代器指向的元素。

template<typename Iter1,typename Iter2>

void iterSwap(Iter1 iter1,Iter2 iter2) {

     T temp = *iter1;

     *iter1 = *iter2;

     *iter2 = temp;

}

那么问题来了,假设你刚好忘记有个东西叫auto,又忘记了有个东西叫decltype,这个时候你的T应该从哪里来呢?明明是一个编译时期肯定能确定的类型,但是却不知从何获取。于是,会整活的人奇思妙想硬是整了出来:

T temp = *iter1; 改为:

typename Iter1::valueType temp = *iter1;

这样只需要在每个Iter类里面typedef XXX valueType; 就可以了。


那么问题又来了,有一天一个傻子往这个函数里面丢了两个指针,然后看着哗哗报错的模板。明明指针和迭代器的行为相似,那怎么同时实现两者呢?于是,聪明的猿人想出了方法把“指针”这个“特性”“萃取”出来,也就是traits。


template<typename Iter>

struct IterTraits {

    typedef typename Iter::valueType valueType;

};

template<typename T>

struct IterTraits<T*> {

    typedef T valueType;

};


之前的代码改为:

typename IterTraits<Iter1>::valueType temp = *iter1;

就可以了。


显然,这里就肯定涉及到了SFINAE(Substition Failure Is Not An Error),不能说在尝试实例化IterTraits的时候,指针尝试选择第一个版本结果出错了,就直接视为错误而停止编译;而是要再接着尝试下面这个版本,发现可以匹配,于是通过。

于是,一个简单的iterSwap实现完毕(例子仅用于示意,实战这么写依然是要被人打死的请注意)


#include <type_traits>

这个头文件存了大量的比较实用的模板,平时想骚一把的可以瞅瞅


std::is_XXX系列模板,比如is_array,一个可能的实现方法:

template<typename T>

struct is_array : std::false_type {};

template<typename T>

struct is_array<T[]> : std::true_type {}; 

template<typename T, std::size_t N>

struct is_array<T[N]> : std::true_type {};



然后是std::conditional,可能的实现有:

template<bool B, typename T, typename F>

struct conditional { typedef T type; };

template<typename T, typename F>

struct conditional<false, T, F> { typedef F type; };

e.g.

typedef std::conditional<USEINT,int,float>::type Type;


接着是std::enable_if,可能的实现有:

template<bool B, class T = void>

struct enable_if {};

template<class T>

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


就是在条件下可以有类似屏蔽类型的效果,可以导致出错然后SFINAE。


大忙人系列-程序猿在想什么 (四·二) C++的食用方法的评论 (共 条)

分享到微博请遵守国家法律