7 模板和泛型编程
条款41:了解隐式接口和编译器多态
面向对象编程世界总是以显式接口和运行期多态解决问题:
class Widget{ public: Widget(); virtual ~Widget(); virutal std::size_t size() const; virtual void normalize(); void swap(Widget& other); //... };
void doProcessing(Widget& w){ if(w.size() > 10 && w != someNastyWidget){ Widget temp(w); temp.normalize(); temp.swap(w); } }
template<typename T> void doProcessing(T& w){ if(w.size() >10 && w != someNastyWidget){ T temp(w); temp.normalize(); temp.swap(w); } }
class Widget{ public: Widget(); virtual ~Widget(); virutal std::size_t size() const; virtual void normalize(); void swap(Widget& other); //... };
template<typename C> void print2nd(const C& container){ if(container.size() >= 2){ C::const_iterator iter(container.begin()); ++iter; int value = *iter; std::cout << value; } }
template<typename C> void print2nd(const C& container){ C::const_iterator* x; }
template<typename C> void print2nd(const C& container){ if(container.size() >= 2){ C::const_iterator iter(container.begin());//这个名称被假设为非类型(??????) } }
现在清楚为什么这不是有效的C++代码了吧。iter声明式只有在C::const_iterator是个类型时才合理,但我们并没有告诉C++说它是,于是C++假设它不是。若要矫正这个形式,我们必须告诉C++说C::const_iterator是个类型。只要在它之前加上typename即可:
template<typename C> void print2nd(const C& container){ if(container.size() >= 2){ typename C::const_iterator iter(container.begin()); ++iter; int value = *iter; std::cout << value; } }
typename必须作为嵌套从属类型名称的前缀词这一规则的例外是,typename不可以出现在base class list内的嵌套从属类型名称之前,也不可以在成员初始化列中作为基类修饰符:
template<typename T> class Derived: public Base<T>::Nested{ //base class list中不允许typename public: explicit Derived(int x) : Base<T>::Nested(x){ //成员初始列中不允许tepename typename Base<T>::Nested temp; //既不在base class list中也不在mem.init.list中 //.. } //.. }
请记住:
1.声明template参数时,关键字class和typename可互换。
2.请使用关键字typename标识嵌套从属类型名;但不得在base class list或者member initialization list内以它作为base class修饰符。