更多 C++ 习惯用法/对象生成器
外观
简化对象创建,无需显式指定类型。(这不是工厂方法模式)
在 C++ 模板编程中,即使在小型程序中,对象的类型也会变得非常庞大且难以理解。例如,以下类型(Wrapper)是一个标准的一元函数对象,它封装了类File中的成员函数read_line。
struct File
{
int read_line (std::string);
};
typedef std::mem_fun1_t<int, File, std::string> Wrapper;
使用for_each STL 算法读取一组文件,在没有对象生成器的情况下,看起来像这样
void read_lines(std::vector<File *> files)
{
typedef std::mem_fun1_t<int, File, std::string> Wrapper;
std::string arg;
for_each(files.begin(), files.end(),
std::binder2nd<Wrapper>(Wrapper(&File::read_line), arg));
}
上面的代码几乎不可读,并且比必要的多余。即使类型定义也不能提高可读性,因为Wrapper之类的占位符类型定义会分散注意力。对象生成器习惯用法可以缓解这种情况。
在对象生成器习惯用法中,会创建一个模板函数,它的唯一作用是从其参数构造一个新对象。它基于函数模板的一个有用属性,而类模板没有:函数模板的类型参数会从其实际参数自动推断出来。例如,考虑 STL 中定义的一个简单的对象生成器:make_pair。
template <class T, class U>
std::pair <T, U>
make_pair(T t, U u)
{
return std::pair <T, U> (t,u);
}
make_pair 返回pair 模板的一个实例,具体取决于make_pair 函数的实际参数。例如,make_pair(1, 1.0) 通过自动推断传递给对象生成器函数的对象类型,创建一个类型为:std::pair<int, double> 的对象。make_pair 在生成的 pair 对象不需要存储在局部变量的情况下特别有用。
map <int, double> m;
m.insert (make_pair(1,1.0)); // No need to know how pair template is instantiated.
C++ 标准库定义了几个对象生成器,以避免代码膨胀。std::bind2nd 和 std::mem_fun 是两个这样的标准对象生成器,可用于避免在上面动机部分所示的示例中代码膨胀。
void read_lines(std::vector<File *> files)
{
std::string arg;
for_each(files.begin(), files.end(), bind2nd(mem_fun(&File::read_line), arg));
}
C++ 标准库 (mem_fun、make_pair、bind1st、bind2nd 等)