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

三. 模板是如何整活的
從一個(gè)簡(jiǎn)單的iterSwap開(kāi)始,假設(shè)能交換兩個(gè)迭代器指向的元素。
template<typename Iter1,typename Iter2>
void iterSwap(Iter1 iter1,Iter2 iter2) {
???? T temp = *iter1;
???? *iter1 = *iter2;
???? *iter2 = temp;
}
那么問(wèn)題來(lái)了,假設(shè)你剛好忘記有個(gè)東西叫auto,又忘記了有個(gè)東西叫decltype,這個(gè)時(shí)候你的T應(yīng)該從哪里來(lái)呢?明明是一個(gè)編譯時(shí)期肯定能確定的類型,但是卻不知從何獲取。于是,會(huì)整活的人奇思妙想硬是整了出來(lái):
T temp = *iter1; 改為:
typename Iter1::valueType temp = *iter1;
這樣只需要在每個(gè)Iter類里面typedef XXX valueType; 就可以了。
那么問(wèn)題又來(lái)了,有一天一個(gè)傻子往這個(gè)函數(shù)里面丟了兩個(gè)指針,然后看著嘩嘩報(bào)錯(cuò)的模板。明明指針和迭代器的行為相似,那怎么同時(shí)實(shí)現(xiàn)兩者呢?于是,聰明的猿人想出了方法把“指針”這個(gè)“特性”“萃取”出來(lái),也就是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),不能說(shuō)在嘗試實(shí)例化IterTraits的時(shí)候,指針嘗試選擇第一個(gè)版本結(jié)果出錯(cuò)了,就直接視為錯(cuò)誤而停止編譯;而是要再接著嘗試下面這個(gè)版本,發(fā)現(xiàn)可以匹配,于是通過(guò)。
于是,一個(gè)簡(jiǎn)單的iterSwap實(shí)現(xiàn)完畢(例子僅用于示意,實(shí)戰(zhàn)這么寫依然是要被人打死的請(qǐng)注意)
#include <type_traits>
這個(gè)頭文件存了大量的比較實(shí)用的模板,平時(shí)想騷一把的可以瞅瞅。
std::is_XXX系列模板,比如is_array,一個(gè)可能的實(shí)現(xiàn)方法:
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,可能的實(shí)現(xiàn)有:
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,可能的實(shí)現(xiàn)有:
template<bool B, class T = void>
struct enable_if {};
template<class T>
struct enable_if<true, T> { typedef T type; };
就是在條件下可以有類似屏蔽類型的效果,可以導(dǎo)致出錯(cuò)然后SFINAE。