C++ STL原来可以这么强大

        今天在做C++ Primer第14章习题14.37的时候用到了一些STL的函数,彻底颠覆了我对C++的看法。以前总觉得C++很麻烦,实现一个功能总要写一堆的代码,很繁琐,那是菜鸟时候的想法。虽然现在也还是菜鸟,但级别比原来提高了一点,今天使用了STL的算法之后才知道,原来C++也可以这么简洁。

        从习题一步步扩展开来讲吧,习题如下:

习题14.37    使用标准库函数对象和函数适配器,定义一个对象用于:

        (a)查找大于1024的所有值

        (b)查找不大于pooth的所有字符串

        (c)将所有值乘以2

        做这题之前先简单介绍一下C++的函数对象和标准库提供的函数适配器。

        C++中函数对象是为实现某种操作而重载调用操作符的类,即重载其operator()操作符函数,必须声明为成员函数。函数对象经常用作通用算法的实参。标准库定义了很多函数对象供程序员使用,在functional头文件里面定义,包含算数函数对象类型、关系函数对象类型和逻辑函数对象类型,这些函数对象有的是一元函数对象,有的是二元函数对象,一元函数对象接受一个实参,二元函数对象接受两个实参。

        STL中提供了很多标准库算法,一般的标准库算法都使用内置的操作,比如<、==等,如果要使用自定义的操作,可以传函数指针,但对函数指针的形参个数有限制,用起来不是很方便。这时候函数对象就可以发挥作用了,可以把多余的参数作为函数对象的内部成员,通过初始化的时候把值传递给函数对象,通过调用函数对象的调用操作符实现比较的目的。

        C++提供了函数适配器来扩展函数对象的使用。因为二元函数对象要传递两个值,如果其中有一个值是已知或者默认的,这时候可以把他初始化,这个功能由绑定器来提供,bind1st用来绑定二元函数对象的第一个实参,bind2nd用于绑定二元函数对象的第二个实参。另外一个适配器是求反器,用于对谓词函数对象的真值求反,not1对一元函数对象求反,not2对二元函数求反。

        简单介绍完基础之后再回来解这习题,来看看STL是怎么让程序变得简洁的。

        对于(a)可以用bind2nd函数适配器和greater<int>函数对象来实现,如下所示:

	// Find the value greater than 1024 with standard function objects and function adaptor
	int nVal[] = {43, 53, 536, 4976, 5307, 32, 536, 957};
	size_t size = sizeof(nVal) / sizeof(int);
	
	cout << "The original value: " << endl;
	for (size_t i = 0; i != size; ++i)
		cout << nVal[i] << " ";
	cout << endl;
		
	int *nFind = nVal;
	int toCompare = 1024;

	cout << "The value that greater than " << toCompare << " : " << endl;
	while ((nFind = find_if(nFind, nVal + size, bind2nd(greater<int>(), toCompare))) != nVal + size)
	{
		cout << *nFind << " ";
		++nFind;
	}
	cout << endl << endl;
        对于(b)可以用bind2nd函数适配器和not_equal_to<string>函数对象来实现,如下所示:

	// Find string not equal with "pooth"
	const int ARYSIZE = 5;
	string sAry[ARYSIZE] = {"abc", "adu", "butterfly", "pooth", "nancy"};
	vector<string> sVec(sAry, sAry + ARYSIZE);

	vector<string>::iterator sIter = sVec.begin();
	cout << "The original string: " << endl;
	while (sIter != sVec.end())
	{
		cout << *sIter << " ";
		++sIter;
	}
	cout << endl;

	cout << "The string that not euqal with \"pooth\" : " << endl;
	sIter = sVec.begin();
	string sToCompare = "pooth";
	while ((sIter = find_if(sIter, sVec.end(), bind2nd(not_equal_to<string>(), sToCompare))) != sVec.end())
	{
		cout << *sIter << " ";
		++sIter;
	}
	cout << endl << endl;

        对于(c)可以用bind2nd函数适配器、transform和multiplies<int>来实现,如下所示:

class PrintVal
{
public:
        PrintVal() { }
        void operator()(int &val) const { cout << val << " "; }
};

// Multiply all the value by 2
vector<int> nVec(nVal, nVal + size);
cout << "The original val: " << endl;
for_each(nVec.begin(), nVec.end(), PrintVal());
cout << endl;
transform(nVec.begin(), nVec.end(), nVec.begin(), bind2nd(multiplies<int>(), 2));
cout << "After multiply by 2: " << endl;
for_each(nVec.begin(), nVec.end(), PrintVal());
cout << endl;








        从上面是不是可以看到,从(a)(b)到(c)是不是代码简洁了很多,通过引入PrintVal函数对象和for_each的使用,大大减少了代码量,使程序看起来简洁易懂。

         整个习题的代码如下所示:

#include <iostream>
#include <functional>
#include <algorithm>
#include <vector>
#include <string>
using namespace std;

class PrintVal
{
public:
	PrintVal() { }
	void operator()(int &val) const { cout << val << " "; }
};

int main()
{
	// Find the value greater than 1024 with standard function objects and function adaptor
	int nVal[] = {43, 53, 536, 4976, 5307, 32, 536, 957};
	size_t size = sizeof(nVal) / sizeof(int);
	
	cout << "The original value: " << endl;
	for (size_t i = 0; i != size; ++i)
		cout << nVal[i] << " ";
	cout << endl;
		
	int *nFind = nVal;
	int toCompare = 1024;

	cout << "The value that greater than " << toCompare << " : " << endl;
	while ((nFind = find_if(nFind, nVal + size, bind2nd(greater<int>(), toCompare))) != nVal + size)
	{
		cout << *nFind << " ";
		++nFind;
	}
	cout << endl << endl;


	// Find string not equal with "pooth"
	const int ARYSIZE = 5;
	string sAry[ARYSIZE] = {"abc", "adu", "butterfly", "pooth", "nancy"};
	vector<string> sVec(sAry, sAry + ARYSIZE);

	vector<string>::iterator sIter = sVec.begin();
	cout << "The original string: " << endl;
	while (sIter != sVec.end())
	{
		cout << *sIter << " ";
		++sIter;
	}
	cout << endl;

	cout << "The string that not euqal with \"pooth\" : " << endl;
	sIter = sVec.begin();
	string sToCompare = "pooth";
	while ((sIter = find_if(sIter, sVec.end(), bind2nd(not_equal_to<string>(), sToCompare))) != sVec.end())
	{
		cout << *sIter << " ";
		++sIter;
	}
	cout << endl << endl;


	// Multiply all the value by 2
	vector<int> nVec(nVal, nVal + size);
	cout << "The original val: " << endl;
	for_each(nVec.begin(), nVec.end(), PrintVal());
	cout << endl;
	transform(nVec.begin(), nVec.end(), nVec.begin(), bind2nd(multiplies<int>(), 2));
	cout << "After multiply by 2: " << endl;
	for_each(nVec.begin(), nVec.end(), PrintVal());
	cout << endl;
	return 0;
}

阅读更多
个人分类: C++
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭