命名参数惯用法(Named Parameter Idiom)解决的问题是:C++函数参数有位置次序性的限制(positional parameters),也就是说,调用C++函数时,你不能只提供几个参数而已,而且你还要提供这几个参数的次序信息,这一点C++不如Ada 编译器内置就提供命名参数(named parameters)功能,这个功能对于实现大量参数的函数,尤其是大量默认参数的函数特别有用「译者:因为参数量大的函数会给调用函数的程序员带来不便」。
多年以来,人们发明了很多方法来弥补这个C++的不足,其中之一就是把参数转储到一个字符串中,然后在运行期再把参数给抽取出来,例如fopen的第二个参数。还有个比较特殊的例子是,把若干个bool参数,放到一个位表(bit-map)中,然后调用时再通过位移来获取原来的参数,例如open函数的第二个参数。这些方法都是为了解决了量大参数函数的问题。但是下面要介绍的命名参数惯用法能更加优雅方便得解决这个问题。
用一句话概况命名参数惯用法,就是把函数参数换成此类的另一个方法,所有这样的方法都返回*this,也就是自己的引用,然后把原来函数的参数全部去掉,变成了一个方法「译者:定义有参数的方法(Method)叫函数(Function)」。
下面举一个用于打开文件的类的实例来说明:
打开一个文件需要文件路径字符串,还有很多可选参数:文件的读写性、文件不存在是否自动创建一个、写文件的位置是文件首端还是末端、创建文件的大小、是否需要IO缓冲区、缓冲区大小、是否能被共享访问,等等...很多。如果按照常规去实现这样一个函数的话,那么代码非常难以阅读,长达8个限制位置次序的参数,使得调用的程序员很容易搞错。所以我们要使用Named Parameter Idiom。
在实现之前,我们先看看实现的结果是怎样的。使用默认参数的情况下,看起来像这样:
如果要指定一串参数,那么就像这样:
这样的话我们可以随便改变这些"参数"的次序(not positional),而且他们都有了可读性较强的名子。
如何来实现呢?首先我们要创建一个OpenFile类,为所有用到的参数建立他们相对应的OpenFile私有数据成员。唯一一个文件路径的参数仍然用传统方式,放在OpenFile的构造函数上,但构造函数并不真正去打开文件。而所有其他的可选参数,都变成了方法,这些方法(如,readonly(),blockSize(unsigned)等),都返回一个OpenFile自身的引用,使得这些方法能够被链式调用(chained)。
另外建立一个File类来接收一个OpenFile对像:
这个类的构造函数来获取所有的参数,来真正打开文件:
注意OpenFile类已经声明了File是它的友元,这样可以方便File获取他的私有成员。
那个链式的方法调用都是使用引用方式,所以没有对象拷贝的开销,效率很高,如果还是inline的,那么就和C差不多高效了。
原文: http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.18
多年以来,人们发明了很多方法来弥补这个C++的不足,其中之一就是把参数转储到一个字符串中,然后在运行期再把参数给抽取出来,例如fopen的第二个参数。还有个比较特殊的例子是,把若干个bool参数,放到一个位表(bit-map)中,然后调用时再通过位移来获取原来的参数,例如open函数的第二个参数。这些方法都是为了解决了量大参数函数的问题。但是下面要介绍的命名参数惯用法能更加优雅方便得解决这个问题。
用一句话概况命名参数惯用法,就是把函数参数换成此类的另一个方法,所有这样的方法都返回*this,也就是自己的引用,然后把原来函数的参数全部去掉,变成了一个方法「译者:定义有参数的方法(Method)叫函数(Function)」。
下面举一个用于打开文件的类的实例来说明:
打开一个文件需要文件路径字符串,还有很多可选参数:文件的读写性、文件不存在是否自动创建一个、写文件的位置是文件首端还是末端、创建文件的大小、是否需要IO缓冲区、缓冲区大小、是否能被共享访问,等等...很多。如果按照常规去实现这样一个函数的话,那么代码非常难以阅读,长达8个限制位置次序的参数,使得调用的程序员很容易搞错。所以我们要使用Named Parameter Idiom。
在实现之前,我们先看看实现的结果是怎样的。使用默认参数的情况下,看起来像这样:
File f
=
OpenFile(
"
foo.txt
"
);
如果要指定一串参数,那么就像这样:
File f
=
OpenFile(
"
foo.txt
"
)
. readonly ()
.createIfNotExist()
.appendWhenWriting()
.blockSize( 1024 )
.unbuffered()
.exclusiveAccess();
. readonly ()
.createIfNotExist()
.appendWhenWriting()
.blockSize( 1024 )
.unbuffered()
.exclusiveAccess();
这样的话我们可以随便改变这些"参数"的次序(not positional),而且他们都有了可读性较强的名子。
如何来实现呢?首先我们要创建一个OpenFile类,为所有用到的参数建立他们相对应的OpenFile私有数据成员。唯一一个文件路径的参数仍然用传统方式,放在OpenFile的构造函数上,但构造函数并不真正去打开文件。而所有其他的可选参数,都变成了方法,这些方法(如,readonly(),blockSize(unsigned)等),都返回一个OpenFile自身的引用,使得这些方法能够被链式调用(chained)。
class
File;
class OpenFile {
public:
OpenFile(const std::string& filename);
// sets all the default values for each data member
OpenFile& readonly(); // changes readonly_ to true
OpenFile& readwrite(); // changes readonly_ to false
OpenFile& createIfNotExist();
OpenFile& blockSize(unsigned nbytes);
...
private:
friend class File;
std::string filename_;
bool readonly_; // defaults to false [for example]
bool createIfNotExist_; // defaults to false [for example]
...
unsigned blockSize_; // defaults to 4096 [for example]
...
} ;
inline OpenFile::OpenFile( const std:: string & filename)
: filename_ (filename)
, readonly_ ( false )
, createIfNotExist_ ( false )
, blockSize_ ( 4096u )
{ }
inline OpenFile & OpenFile:: readonly ()
{ readonly_ = true; return *this; }
inline OpenFile & OpenFile::readwrite()
{ readonly_ = false; return *this; }
inline OpenFile & OpenFile::createIfNotExist()
{ createIfNotExist_ = true; return *this; }
inline OpenFile & OpenFile::blockSize(unsigned nbytes)
{ blockSize_ = nbytes; return *this; }
class OpenFile {
public:
OpenFile(const std::string& filename);
// sets all the default values for each data member
OpenFile& readonly(); // changes readonly_ to true
OpenFile& readwrite(); // changes readonly_ to false
OpenFile& createIfNotExist();
OpenFile& blockSize(unsigned nbytes);
...
private:
friend class File;
std::string filename_;
bool readonly_; // defaults to false [for example]
bool createIfNotExist_; // defaults to false [for example]
...
unsigned blockSize_; // defaults to 4096 [for example]
...
} ;
inline OpenFile::OpenFile( const std:: string & filename)
: filename_ (filename)
, readonly_ ( false )
, createIfNotExist_ ( false )
, blockSize_ ( 4096u )
{ }
inline OpenFile & OpenFile:: readonly ()
{ readonly_ = true; return *this; }
inline OpenFile & OpenFile::readwrite()
{ readonly_ = false; return *this; }
inline OpenFile & OpenFile::createIfNotExist()
{ createIfNotExist_ = true; return *this; }
inline OpenFile & OpenFile::blockSize(unsigned nbytes)
{ blockSize_ = nbytes; return *this; }
另外建立一个File类来接收一个OpenFile对像:
class
File {
public :
File( const OpenFile & params );
...
};
public :
File( const OpenFile & params );
...
};
这个类的构造函数来获取所有的参数,来真正打开文件:
File::File(
const
OpenFile
&
params
)
{
...
}
{
...
}
注意OpenFile类已经声明了File是它的友元,这样可以方便File获取他的私有成员。
那个链式的方法调用都是使用引用方式,所以没有对象拷贝的开销,效率很高,如果还是inline的,那么就和C差不多高效了。
原文: http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.18