template <size_t N> class bitset;
当然,其中的N必须是一个编译器常量(即能够在编译器就确定变量的值)。
2、缺省模板参数(Default Template Parameters)
1)类模板可以有缺省的模板参数;
2)但函数模板不能有缺省的模板参数。
3、成员模板(Member Template )
类的成员函数可以是一个模板函数。但这样的函数既不能是virtual也不能有缺省参数。
例如:
1) 类为实例类:
class MyClass
{
....
tempate<typename T>
void fun(const T &);
....
};
2)类为模板类:
template <typename T>
class MyClass
{
private:
T value;
public:
void assign(const MyClass<T> &other ); // other 必须和 *this 具有严格一样的类型
template <typename U>
void assign(const MyClass<U> &rhs); // rhs 不一定和 *this 具有严格一样的类型,只要成员可被赋值(assignable)即可
};
3) Template Constructor
模板构造函数(template constructor)是模板成员函数的一种特殊形式。模板构造函数通常用于“在复制对象时实现(相似类型的)隐式转换”。注意,模板构造函数并不会隐藏(hide)隐式的拷贝构造函数(implicit copy constructor)。如果类型完全吻合,implicit copy constructor 就会被产生出来并被调用。
4、基本类型的显示初始化
void test_initial()
{
int i1; // undefined value
cout << "i1=" << i1;
int i2 = int(); // i2 == 0
cout << "i2=" << i2;
}
该特性的意义:
这个特性可以确保我们在撰写template程序代码时,任何类型都有一个确切的初始值。例如,下列函数中x被保证初始化为零。
template <class T>
void f()
{
T x = T(); // x 将被正确的初始化
....
}
5、命名空间
namespace,将不同的标志符号集合在一个具名作用域(named scope)内。
using declaration, 通过using声明,我们可以避免一再写出冗长的namespace名称。例如以下声明:
using josuttis::File;
会使File成为当前作用域内代表josuttis::File的一个同义字。
6、pair 的模板(拷贝)构造函数:
template<class U, class V> pair (const pair<U,V>& pr);
7、智能指针
#include <memory> // std::auto_ptr
#include <tr1/memory> // std::tr1::shared_ptr
8、数值极限(Numeric Limits)#include <boost/scoped_ptr.hpp> // boost::scoped_ptr
头文件:
#include <limits>
类模板:
9、辅助函数std::numeric_limits<T>
#include <algorithm> // std::min std::max
template <class T> const T& min (const T& a, const T& b);
template <class T> const T& max (const T& a, const T& b);
10、两值互换函数template <class T, class Compare> const T& min (const T& a, const T& b, Compare comp);template <class T, class Compare> const T& max (const T& a, const T& b, Compare comp);
#include <algorithm> // std::swap
template <class T> void swap (T& a, T& b); // C++98
header | // moved from <algorithm> to <utility> in C++11 |
---|---|
non-array (1) | template <class T> void swap (T& a, T& b) noexcept (is_nothrow_move_constructible<T>::value && is_nothrow_move_assignable<T>::value); |
array (2) | template <class T, size_t N> void swap(T (&a)[N], T (&b)[N]) noexcept (noexcept(swap(*a,*b))); |
1)对于非基本类型的T来说,只有当T的copy构造和assignment操作行为存在时,swap才能达到预期的目的。
2)swap()的模板特化技术——能带来效率上的提升。针对特定的类撰写特定的swap()函数。
11、辅助型的比较操作符在C++标准程序库的<utility>模块中,定义了 !=, >, <=, >= 四个模板函数,他们都是利用类型各自的 == 和 < 操作符来完成的。
值得注意的是,这四个比较操作符都位于std::rel_ops的次命名空间中。这里为什么要使用次命名空间?为了防止和用户定义的全局命名空间中的同类型操作符发生冲突。
12、头文件 <cstddef>#include <utility> // 头文件using namespace std::rel_ops; // !=, >, <=, >= 四个模板函数所在的次命名空间
定义了常用的常量 NULL, size_t, ptrdiff_t, offsetof 等.
13、头文件 <cstdlib>
1) 定义了 EXIT_SUCCESS, EXIT_FAILURE用来当作exit(int status)的参数, 也可以当作main()的返回值。
2) abort.
3) atexit(void (* function) () ) : 经由 atexit() 登录的函数,在程序正常退出时会依照登录的相反次序被一一调用。
14、STL
STL是C++标准程序库的核心,它深刻影响了标准程序库整体结构。STL包括容器containers、迭代器iterators、仿函数functors、算法algorithms等部分。STL赋予C++新的抽象层次。STL的基本观念是将数据和算法分离。数据由容器管理;而操作由可定制的算法定义之;迭代器则在二者之间充当粘合剂。STL这种将数据和操作(算法)分开对待,而不是合并考虑。因此从这种意义上讲,STL的概念和面向对象编程(OOP)的最初思想是矛盾的。这么做的原因是追究更大的灵活性和弹性。STL是泛型编程的一个杰出范例。
15、容器
文档详细。
16、关于前置式递增/减和后置式递增/减的效率问题:前置式递增/减效率更高,因为后置式递增/减需要一个额外的临时对象。因此建议优先使用前置式递增/减操作符。
17、算法(Algorithms)
魅力无穷,多多尝试,渐渐熟悉。
18、算法 vs 成员函数
就算我们符合种种条件,得以使用某个算法,那也不一定就合适。容器本身可能提供功能相似且性能更佳的成员函数。当然,凡事都有利弊。
利:性能优良。
弊:由于使用了特定容器的特定成员函数。因此,以后如果想换用另一种容器,就不得不改动程序代码。
在我看来,这个弊端给程序员带来的危害很小,因为一旦更换容器,编译器会告诉我们那些代码(接口)需要更改。因此,应该优先使用成员函数——这是做出不必要的劣化。
19、自定义泛型函数(User-Defined Generic Functions)
为了在这些操作之中声明有效的迭代器,我们必须使用容器提供的类型,因为每一种容器都有自己的迭代器。为了让我们方便写出真正的泛型函数,每一种容器都提供了一些内部类型定义。
20、判断式(Predicates, 谓词)
所谓Predicates,就是返回布尔值(boolean)的函数。他们通常被用来指定排序准则和搜寻准则。Predicates可能有一个或两个操作数,视具体情况而定。注意,并非任何返回布尔值的一元函数或二元函数就是合法的Predicates。STL要求,面对相同的输入值,Predicates必须得出相同的结果。这条戒律将那些“被调用时会改变自己内部状态”的函数清除出场。
21、关于计算绝对值函数 abs()
1、C++98
#include <cstdlib> /* abs */
int abs ( int n); long int abs (long int n);
#include <cmath> // std::abs
double abs (double x); float abs (float x); long double abs (long double x);double fabs (double x); float fabs (float x); long double fabs (long double x);此外,还有#include <stdlib.h> /* labs */
long int labs (long int n);这么多的*abs(), 不明究里。不过,我们需要知道, 对于*abs()不同的重载形式和函数前面,其位于不同的头文件中。
22、仿函数
通常的说,仿函数比函数具有更普遍的适用性和诸多优点。