Tuples Herb Sutter
副标题#e#
就像我上期所报道的一样,在2002十月尺度集会会议上,两个库扩展作为尺度库延深,而被通过。
1 是Doug Gregor’s提出的多态函数的object wrappers。
2 Jaakko Järvi’s提出的tuple范例。
这两个都是直接来在Boost项目。(Boost项目是一个C++ libraries 荟萃)上次,我承诺在这期和下一期将先容这两个扩展的库,这个月,就让我来简朴的先容一下tuple范例。
Tuple Types:一个简朴Motivating例子
如果你想用一个函数返回多于一个返回值,譬喻:
// yields a quotient only
//
int IntegerDivide( int n, int d ) {
return n / d;
}
// Sample use:
cout << "quotient = " << IntegerDivide( 5, 4 );
在这个实现中有什么错误吗? 也许没有,究竟在编译器中,我们内嵌了整数除法。包罗功效也可以或许四舍五入。
可是,假如我们想做更多。出格,想提供一个要领获得除法其他的信息,譬喻除法的余数。假如没有改变函数的布局。那么,实现这样的要求的函数不是一件容易的工作。
一种步伐我们在函数中插手一个输出变量。
// Example 1(b): Integer division,
// yielding a quotient and remainder,
// one as the return value and one via
// an output parameter
//
int IntegerDivide( int n, int d, int& r ) {
r = n % d;
return n / d;
}
// Sample use:
int remainder;
int quotient = IntegerDivide( 5, 4, remainder );
cout << "quotient = " << quotient
<< "remainder = " << remainder;
这个要领的实现较量,可是我们常常这么实现。这种通过返回值和输出变量来返回函数返回值的步伐,看起来有点不行思议。有人也许会说下面的步伐更好。
// Example 1(c): Integer division,
// yielding a quotient and remainder,
// this time via two output parameters
//
void IntegerDivide( int n, int d, int& q, int& r ) {
r = n % d;
q = n / d;
}
// Sample use:
int quotient, remainder;
IntegerDivide( 5, 4, quotient, remainder );
cout << "quotient = " << quotient
<< "remainder = " << remainder;
这种步伐也许越发协调。可是 照旧较量暗昧,不令人满足。稍微想一想,我们会记得为什么:Ralph Waldo Emerson发起我们:“一个愚笨的一致性的想法是思想杂乱的怪物”(a foolish consistency is the hobgoblin of little minds)。这个版本可以或许正常事情,可是,假如你认为它不不变的话,我不会责怪你。
那么该怎么做呢?在这一点我们凡是会想起在尺度库中我们有一个东西:std::pair,究竟在尺度模板库中有许多函数可以返回几个值 ,iterator范畴就是作为一个单独的值-同时,大多通过pair<iterator,iterator>实现的,同样的要领可以或许运行,如下:
// Example 1(d): Integer division,
// yielding a quotient and remainder,
// this time both in the return value
//
std::pair<int,int> IntegerDivide( int n, int d ) {
return pair<int,int>( n/d, n%d );
}
// Sample use:
pair<int, int> quot_rem = IntegerDivide( 5, 4 );
cout << "quotient = " << quot_rem.first
<< "remainder = " << quot_rem.second;
可以看出这是一个满足的做法,同时,它还可以提高。
#p#副标题#e#
Tuples in Action
一些语言,包罗Haskell, ML, 以及Python,都直接支持tuple types。C++不是这样,这是因为C++是一个能做任何工作,和内建尺度库的系统语言,因此,我们可以或许,以库的形式实现我们本身的tuple types。像java等语言是把tuple type作为pair一个系列打包在一起。一个 tuple
type和“bundle-o-values”很相像。
在下面一个tuple-ized 的IntegerDivide例子和上面pair-ized 是很相像的,可是,我们不要被疑惑了,究竟它利用的是一种新的要领:
// Example 2(a): Integer division,
// yielding a quotient and remainder,
// via a type return type
//
tuple<int,int> IntegerDivide( int n, int d ) {
return tuple<int,int>( n/d, n%d );
}
// Sample use:
tuple<int, int> quot_rem = IntegerDivide( 5, 4 );
cout << "quotient = " << quot_rem.get<0>()
<< "remainder = " << quot_rem.get<1>();
这个例子的语法没有pair那么优雅,可是,它却是和pairs一样的简朴好用。
另一方面,typle 不范围于只有两个成员,它可以有任意多的成员,因此,它可以绑缚任何多个数值,我们来看下面的例子:
#p#分页标题#e#
// Example 2(b): Floating-point division,
// yielding a quotient and remainder,
// but also an underflow
//
tuple<float, float, bool> // quotient, remainder, underflow
FloatDivide( float n, float d ) {
// —
}
假如,我们利用std::pair来实现的话,那么将会是这样,std::pair<float, std::pair<float, bool> >, (译注:这样各人也许可以或许看出tuple的优势了把)
可是,我们不能总是把tuple作为bundle-o-values来利用。这里有一些要领把来说奈何把一些独立的变量绑缚成tuple 。这是对付绑缚数值息争绑数值都是有用。譬喻,我们回到第一个关于除律例子 。
// Example 3: Bundling and unbundling
// using "tie"
//
tuple<int,int> IntegerDivide( int n, int d ) {
return tuple<int,int>( n/d, n%d );
}
// Sample use:
int quotient, remainder;
tie( quotient, remainder ) = IntegerDivide( 5, 4 );
cout << "quotient = " << quotient
<< "remainder = " << remainder;
通过这种要领,我们就不消写那些我们不喜欢写的输出变量了,Tuples有本身的输入,输出标记,息争压操纵标记。
// Example 4(a): Streaming tuples
//
tuple<int, int> quot_rem = IntegerDivide( 5, 4 );
cout << quot_rem; // "(1 1)"
另一方面,假如,你想发挥一下你才智的话,你可以节制括号,和分界符。
// Example 4(b): Customizing streamed tuples
//
tuple<int, int> quot_rem = IntegerDivide( 5, 4 );
cout << tuples::set_open('['] << tuples::set_close(')')
<< tuples::set_delimiter(',')
<< quot_rem; // "[1,1]"
你假如有乐趣,你可以参考Boost中tuple的实现,(www.boost.org),