The C++ Standard Library : A Tutoral and Reference 读书笔记之序偶(Pair)
类pair提供了这样一种机制,它把两个(有序)值作为一个单元对待.在c++标准库中,它被广泛的应用.特别是在容器类map和multimap中大量的使用了pair来管理它们的元素.另外一个对于pair的广泛使用就是在那些要返回两个值的函数中.
结构pair被定义在<utility>中,如下:
namespace
std {
template < class T1, class T2 >
struct pair {
// type names for the values
typedef T1 first_type;
typedef T2 second_type;
// member
T1 first;
T2 second;
/* default constructor
* - T1 () and T2 () force initialization for built-in types
*/
pair()
: first(T1()), second(T2()) {
}
// constructor for two values
pair( const T1 & a, const T2 & b)
: first(a), second(b) {
}
// copy constructor with implicit conversions
template < class U, class V >
pair( const pair < U,V >& p)
: first(p.first), second(p.second) {
}
};
// comparisons
template < class T1, class T2 >
bool operator == ( const pair < T1,T2 >& , const pair < T1,T2 >& );
template < class T1, class T2 >
bool operator < ( const pair < T1,T2 >& , const pair < T1,T2 >& );
//
similar: !=, <=, >, >=
// convenience function to create a pair
template < class T1, class T2 >
pair < T1,T2 > make_pair ( const T1 & , const T2 & );
}
注意pair被定义为struct而不是class,这就是说访问pair中任何一个单独的值都是可以的.默认的构造函数会调用模板类型中默认的构造函数.当然,它也会初始化基本类型如int为默认的值.比如:
template < class T1, class T2 >
struct pair {
// type names for the values
typedef T1 first_type;
typedef T2 second_type;
// member
T1 first;
T2 second;
/* default constructor
* - T1 () and T2 () force initialization for built-in types
*/
pair()
: first(T1()), second(T2()) {
}
// constructor for two values
pair( const T1 & a, const T2 & b)
: first(a), second(b) {
}
// copy constructor with implicit conversions
template < class U, class V >
pair( const pair < U,V >& p)
: first(p.first), second(p.second) {
}
};
// comparisons
template < class T1, class T2 >
bool operator == ( const pair < T1,T2 >& , const pair < T1,T2 >& );
template < class T1, class T2 >
bool operator < ( const pair < T1,T2 >& , const pair < T1,T2 >& );

// convenience function to create a pair
template < class T1, class T2 >
pair < T1,T2 > make_pair ( const T1 & , const T2 & );
}
std::pair<int,float> p;
这样的结果就是p.first=0,p.second=0
上面的带模板的拷贝构造函数是在隐式类型转换的时候使用的.如:
void
f(std::pair
<
int
,
const
char
*>
);
void g(std::pair < const int .std:: string > );

void foo {
std::pair < int , const char *> p( 42 , " hello " );
f(p); // OK: calls built-in default copy constructor
g(p); // OK: calls template constructor
}
上面的例子还不能说明问题,下面我自己实现一个pair:
void g(std::pair < const int .std:: string > );

void foo {
std::pair < int , const char *> p( 42 , " hello " );
f(p); // OK: calls built-in default copy constructor
g(p); // OK: calls template constructor
}
template
<
class
T1,
class
T2
>
class MyPair
{
public :
T1 first;
T2 second;
MyPair():first(T1()),second(T2())
{
std::cout << " first constructor " << std::endl;
}
MyPair( const T1 & a, const T2 & b):first(a),second(b)
{
std::cout << " second constructor " << std::endl;
}
template < class U, class V >
MyPair( const MyPair < U,V > & myP):first(myP.first),second(myP.second)
{
std::cout << " third constructor " << std::endl;
}
};
相应f()和g()也进行一番改动:
class MyPair
{
public :
T1 first;
T2 second;
MyPair():first(T1()),second(T2())
{
std::cout << " first constructor " << std::endl;
}
MyPair( const T1 & a, const T2 & b):first(a),second(b)
{
std::cout << " second constructor " << std::endl;
}
template < class U, class V >
MyPair( const MyPair < U,V > & myP):first(myP.first),second(myP.second)
{
std::cout << " third constructor " << std::endl;
}
};
void
f(MyPair
<
int
,
const
char
*>
arg)
{
std::cout << arg.first << " , " << arg.second << std::endl;
}
void g(MyPair < int ,std:: string > arg)
{
std::cout << arg.first << " , " << arg.second << std::endl;
}
这是调用过程:
{
std::cout << arg.first << " , " << arg.second << std::endl;
}
void g(MyPair < int ,std:: string > arg)
{
std::cout << arg.first << " , " << arg.second << std::endl;
}
int
main()
{
MyPair < int , const char *> p( 100 , " Hello World " );
f(p);
g(p);
}
这是调用结果:
{
MyPair < int , const char *> p( 100 , " Hello World " );
f(p);
g(p);
}
second constructor
100,Hello World
third constructor
100,Hello World
可以看到f(p)的参数的模板类与之前构造的模板类相同,所以会调用默认的构造函数进行复制.
但是g(p)的参数的模板类与之前构造的模板类不同,所以会调用带模板定义的拷贝构造函数进行复制.
序偶的比较
两个序偶相同,当且仅当两个序偶中对应的值相同.
namespace
std {
template < class T1, class T2 >
bool operator == ( const pair < T1,T2 >& x, const pair < T1,T2 >& y) {
return x.first == y.first && x.second == y.second;
}
}
比较两个序偶的大小,第一个元素有较高的优先级,第一个元素小的序偶小,如果第一个元素相等,则比较第二个.
template < class T1, class T2 >
bool operator == ( const pair < T1,T2 >& x, const pair < T1,T2 >& y) {
return x.first == y.first && x.second == y.second;
}
}
namespace
std {
template < class T1, class T2 >
bool operator < ( const pair < T1,T2 >& x, const pair < T1,T2 >& y) {
return x.first < y.first ||
( ! (y.first < x.first) && x.second < y.second);
}
}
一个方便的构造序偶的函数make_pair
template < class T1, class T2 >
bool operator < ( const pair < T1,T2 >& x, const pair < T1,T2 >& y) {
return x.first < y.first ||
( ! (y.first < x.first) && x.second < y.second);
}
}
std::make_pair(42,'@')可以用来取代std::pair<int,char>(42.'@')
make_pair的定义:
namespace
std {
// create value pair only by providing the values
template < class T1, class T2 >
pair < Tl,T2 > make_pair ( const T1 & x, const T2 & y) {
return pair < T1,T2 > (x, y);
}
}
但是在某些情况下,你可能需要显式的定义类型,这个时候make_pair往往不会产生预期的结果:
// create value pair only by providing the values
template < class T1, class T2 >
pair < Tl,T2 > make_pair ( const T1 & x, const T2 & y) {
return pair < T1,T2 > (x, y);
}
}
std::pair<int,float>(42,7.77) 与
std::make_pair(42,7.77) 所产生的pair并不相同,因为后者等效于std::pair<int, double>(42,7,77)