带有参数的流操纵器如何工作

How do stream manipulators with arguments work?

本文关键字:何工作 工作 参数 操纵      更新时间:2023-10-16

在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_baseint,并通过引用返回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);
}

编译器可以从左侧的流中推断出ChTr。 在这种情况下,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 )