模板技巧性基础知识
2012-08-14 13:19
134 查看
1. 关键字typename
SubType是定义于类T内部的一种类型。因此ptr是一个指向T:SubType类型的指针。但是如果缺少typename,SubType就会被认为是一个静态成员,那么它应该是一个具体的变量或对象,于是,下面表达式:
T::SubType* ptr;
就会被看作是类T的静态成员SubType和ptr的乘积。
2. 使用this->
对于具有基类的类模板,自身使用名称x并不一定等同于this->x。即使该x是从基类继承获得的,也是如此。
GCC将无法查找到a的定义(请注意VC可能编译通过,在于VC编译器只扫描template一次)。对于那些在基类中声明,并且依赖于模板参数的符号(函数或变量等),你应该在它们前面使用this->或者Base<T>::。
3. 使用字符串作为函数模板的实参
有时,将字符串传递给函数模板的引用参数会导致出人意料的运行结果。
问题在于:由于长度的不同,这些字符串属于不同的数组类型。也就是说,"apple"和"peach"属于相同的类型const char[6];然而"tomato"的类型是const char[7]。因此只有第一个调用是合法的,因此该max()模板期望的是类型完全相同的参数。然而,如果声明的是非引用参数,就可以使用长度不同的字符串来作为max的参数。
产生这种调用结果的原因在于:<strong>对于非引用类型的参数,在实参演绎的过程中,会出现数组到指针的类型转换</strong>。
x in ref(T const&) : char[6]
x in nonref(T): const char*
你可以选择以下几种方案:
1) 使用非引用参数,取代引用参数(然而,这会导致无用的拷贝)。
2) 进行重载,编写接受引用参数和非引用参数的两个重载参数(然而,这会导致二义性)。
3) 对具体类型进行重载(譬如对std::string进行重载)。
4) 重载数组类型,譬如:
5) 强制要求应用程序使用显式类型转换。
另外一点要注意的是,无论如何为字符串提供重载是有必要的:因为如果不提供重载,当我们调用max()来比较两个字符串时,操作a<b执行的是指针比较,就是a<b比较的是两个字符串的地址,而不是它们的字典顺序。
template <typename T> class MyClass { typename T::SubType* ptr; ... };
SubType是定义于类T内部的一种类型。因此ptr是一个指向T:SubType类型的指针。但是如果缺少typename,SubType就会被认为是一个静态成员,那么它应该是一个具体的变量或对象,于是,下面表达式:
T::SubType* ptr;
就会被看作是类T的静态成员SubType和ptr的乘积。
2. 使用this->
对于具有基类的类模板,自身使用名称x并不一定等同于this->x。即使该x是从基类继承获得的,也是如此。
template <typename T> class Base { public: int a; }; template <typename T> class Derived : public Base<T> { public: void Print() { std::cout << a << "\n"; } };
GCC将无法查找到a的定义(请注意VC可能编译通过,在于VC编译器只扫描template一次)。对于那些在基类中声明,并且依赖于模板参数的符号(函数或变量等),你应该在它们前面使用this->或者Base<T>::。
3. 使用字符串作为函数模板的实参
有时,将字符串传递给函数模板的引用参数会导致出人意料的运行结果。
template <typename T> inline T const& max(T const& a, T const& b) { return a < b ? b : a; } int main() { std::string s; ::max("apple", "peach"); // OK ::max("apple", "tomato"); // ERROR ::max("apple", s); // ERROR }
问题在于:由于长度的不同,这些字符串属于不同的数组类型。也就是说,"apple"和"peach"属于相同的类型const char[6];然而"tomato"的类型是const char[7]。因此只有第一个调用是合法的,因此该max()模板期望的是类型完全相同的参数。然而,如果声明的是非引用参数,就可以使用长度不同的字符串来作为max的参数。
template <typename T> inline T max(T a, T b) { return a < b ? b : a; } int main() { std::string s; ::max("apple", "peach"); // OK ::max("apple", "tomato"); // OK ::max("apple", s); // ERROR }
产生这种调用结果的原因在于:<strong>对于非引用类型的参数,在实参演绎的过程中,会出现数组到指针的类型转换</strong>。
template <typename T> void ref(const T& x) { std::cout << "x in ref(T const&): " << typeid(x).name() << "\n"; } template <typename T> void nonref(T x) { std::cout << "x in nonref(x): " << typeid(x).name() << "\n"; }
x in ref(T const&) : char[6]
x in nonref(T): const char*
你可以选择以下几种方案:
1) 使用非引用参数,取代引用参数(然而,这会导致无用的拷贝)。
2) 进行重载,编写接受引用参数和非引用参数的两个重载参数(然而,这会导致二义性)。
3) 对具体类型进行重载(譬如对std::string进行重载)。
4) 重载数组类型,譬如:
template <typename T, int N, int M> T const* max(T const (&a) , T const (&b)[M]) { return a < b ? b : a; }
5) 强制要求应用程序使用显式类型转换。
另外一点要注意的是,无论如何为字符串提供重载是有必要的:因为如果不提供重载,当我们调用max()来比较两个字符串时,操作a<b执行的是指针比较,就是a<b比较的是两个字符串的地址,而不是它们的字典顺序。
相关文章推荐
- 模板笔记004 - 技巧性基础知识
- C++基础——关于模板的技巧性基础知识(typename、成员模板、模板的模板参数)
- DIY--记一次改造NHibernate模板的经历--预备基础知识
- 【c++ templates读书笔记】【4】技巧性基础知识
- 模板……基础知识笔记
- 函数的模板1——基础知识
- 【c++ templates读书笔记】【4】技巧性基础知识
- CPP Templates 之 技巧性基础知识
- C++ 函数模板基础知识
- 网站模板配色基础知识:心理学色彩理论
- c++之基础知识(1)定义类的对象;析构函数和构造函数常用模板
- ec 模板基础知识
- C++ 模板基础知识
- FreeMarker基础入门知识5 -在模板中定义变量
- SSM框架day01——032——缺省适配器设计模式、033——模板方法设计模式基础知识
- [c++][template]模板基础知识
- 模板笔记005 - 实战基础知识
- C++ Templates笔记 8 技巧性基础知识关键字typename
- 前端学习——css基础知识与html模板
- 关于模板匹配的基础知识