在Stroustrup C++书中,有一个自定义操纵器接受参数的例子(请参阅随附的代码(。我对结构的创建方式感到困惑。特别是,看起来"smanip"的构造函数有两个int参数,一个用于函数指针"ff",一个用于"ii"。我不明白如何使用以下命令传递 int 参数来创建结构:
cout << setprecision(4) << angle;
此外,调用这些函数的顺序是什么,类型参数 Ch 和 Tr 是如何确定的? 多谢。
// manipulator taking arguments
struct smanip{
iso_base& (*f) (ios_base&, int);
int i;
smanip(ios_base& (*ff)(ios_base&, int), int ii) : f(ff), i(ii){}
};
template<cladd Ch, class Tr>
ostream<Ch, Tr>& operator<<(ostream<Ch, Tr>& os, smanip& m){
return m.f(os, m.i);
}
ios_base& set_precision(ios_base& s, int n){
return s.setprecision(n); // call the member function
}
inline smanip setprecision(int n){
return smanip(set_precision,n);
}
// usage:
cout << setprecision(4) << angle;
setprecision(4)
调用
inline smanip setprecision(int n){
return smanip(set_precision,n);
}
这会创建一个从指向set_precision
函数的指针smanip
,并n
.
struct smanip{
ios_base& (*f) (ios_base&, int);
int i;
smanip(ios_base& (*ff)(ios_base&, int), int ii) : f(ff), i(ii){}
};
smanip
是一个结构,用于保存指向函数的指针和一个整数。 该函数通过引用获取ios_base
和int
,并通过引用返回ios_base
。
此时,该行实际上是这样的:
smanip m(&setprecision, 4);
cout << m << (otherstuff);
与此模板匹配:
template<class Ch, class Tr>
ostream<Ch, Tr>& operator<<(ostream<Ch, Tr>& os, smanip& m){
return m.f(os, m.i);
}
编译器可以从左侧的流中推断出Ch
和Tr
。 在这种情况下,std::cout
. 代码执行m.f(os, m.i)
. 这调用smanip
持有的函数指针,将流和smanip
持有的整数传递给它。
ios_base& set_precision(ios_base& s, int n){
return s.setprecision(n); // call the member function
}
这称为cout.setprecision(n)
.
所以这条线翻译为:
std::cout.setprecision(4) << angle;
操纵器函子将函数指针和 int 作为参数,并在内部存储两者以供以后使用。为了便于阅读,可以在以下两个声明中拆分构造函数的签名:
typedef ios_base& (*f_ptr)(ios_base&,int);
smanip( f_ptr f, int )
也就是说,第一个参数是函数指针,第二个参数是值。
按照示例代码中的执行顺序,首先调用函数setprecision
,该函数将函数指针和值存储在smanip
对象中并返回它。对象被传递给适当的operator<<
,该提取并执行传递参数的当前流上的存储函数指针。
// on the calling end
setprecision(4) // --> construct __s = smanip( set_precision, 4 )
(cout << ) // --> passes __s to `operator<<`
// inside operator<<
return m.f( os, m.i ); // calls: set_precision( os, 4 ) (m.f == &set_precision
// m.i == 4 )