条款41:了解隐式接口和编译器多态
Template<typename T> Void doProcessing (T& t) { If (w.size() > 10 && w != someNastyWidget) { T temp(w); Temp.normalize(); Temp.swap(w); } } |
必须支持:size、normalize、swap、拷贝构造、不等判断
这一组表达式是T必须支持的一组隐式接口
凡设计w的任何函数调用,operator> operator!=,可能造成template具现化,是调用成功。这些具现化发生在编译时期。“以不同的template参数具现化function template”,会导致调用不同的函数。这是所谓的编译器多态。
运行期多态、编译期多态差异:virtual(运行期)、template(编译期),差异明显
显示接口、隐式接口:
显示接口由函数的签名(返回值、名称、参数、常量性)构成。
隐式接口不基于签名式,而是有效表达式
Template<typename T>
Void doProcessing (T& t)
{If (w.size() > 10 && w !=someNastyWidget)…}
它必须提供一个名为size的成员函数,该函数返回int类型
它必须提供一个支持operator!=函数,用来比较两个对象
函数可能从父类中继承而来。
对于class和template:
都支持多态和接口
class的接口是显式的,以函数签名为中心,多态则是virtual函数发生于运行期
template的接口是隐式的,基于有效表达式,多态是在编译期通过template具现化和函数重载解析实现
条款42:了解typename的双重定义
template<typename T>
template<classs T>
两者没有区别。
vector<int> vec;
vector<int>::const_iterator itr = vec.begin();
可以访问vec中的元素,但不能修改
const int * conPtr;
说明某个name是个类型,要在其前面加typename
typenameC::const_iterator itr;
Template<typename C> Void f(const C& container, typename C::iterator iter); |
typename必须作为嵌套从属类型名称的前缀词
例外:typename不可以出现在baseclasses list内的嵌套从属类型名称之前,也不可以出现在成员初始化列表中作为base class的修饰符
Template <typename T> Class Derived:public Base<T>::Nested // 不能出现在继承列表中 { Public: Explicit Derived(int x): Base<T>::Nested(x) // 不能出现在初始化列表中 { Typename Base<T>::Nested temp; // 其他位置需要 } }; Template<typename IterT> Void workWithIterator(IterT iter) { Typename std::iterator_traits<IterT>::value_type temp(*iter); //类型IterT对象所指之物的类型 } Template<typename IterT> Void workWithIterator(IterT iter) { Typedef typename std::iterator_traits<IterT>::value_type value_type; Value_type temp(*iter); } |
emplate内出现的名称如果相依于某个template参数,称之为从属名称(dependent names),如果从属名称在class内呈嵌套关,则称之为嵌套从属名称(nested dependent name)。如果解析器在template中遭遇一个嵌套从属名称,它便假设这名称不是个类型,除非你明确告诉它是,做法是在它之前放置关键字typename。typename只能被用来验明嵌套从属类型名称,其他名称不该有它存在。同时,typename不可以出现在baseclass list内的鞋套从属类型名称之前,也不可在member initialization list中作为baseclass修饰符
template<typename C> void print2nd( const C& container ){ if( container.size() >= 2 ){ //C::const_iterator即为一个嵌套从属名称, //编译器默认假设它不是个类型 //因此这段代码不合法 C::const_iterator iter(container.begin()); ++iter; int value = *iter; std::cout<<value; } } //修改一下: template<typename C> void print2nd( const C& container ){ if( container.size() >= 2 ){ //在C::const_iterator前放置关键字typename //明确说明该嵌套从属名称是一种类型。 typename C::const_iterator iter(container.begin()); ... } } //typename不能出现在base class list或member initialization list中 template<typename T> class Derived: public Base<T>::Nested{ public: explicit Derived( int x ): Base<T>::Nested(x){ typename Base<T>:Nested temp; ... } }; //如果编译器不知道Base<T>::nested是什么,可以在前面先用typedef typedef typename Base<T>::Nested Nested;
//然后凡需要Base<T>::Nested的地方则使用Nested。 |
条款43:学习处理模版化基类内的名称
条款44:将与参数无关的代码抽离template
抽离共同部分,形成新函数
条款45:运用成员函数模版接收所有兼容类型
成员函数模版
Template <typename T> Class SmartPtr { Public: Template<typename U> SmartPtr(const SmartPtr<U> &other); // 对于任何的T、U,可以根据S<U>生成S<T> }; |