文章目录

  • 概要介绍
  • find_if 函数
  • 单独函数专门处理
  • 参考文章附录


概要介绍

  我们都熟知 STL 中模板库的std::map可以按key查找对应的值,有些应用中可能会出现 Value 也是唯一的需求状态,举例而言,如果Value中保存的是GUID等唯一性数值,那么key-value 对应关系就从1:N 变成了 1:1。

  如果想要以key查找,那么find已经足够了,如果想按value查找,那就得研究下find_if函数了。

find_if 函数

template <class InputIterator, class Predicate> 
InputIterator find_if(InputIterator first, InputIterator last,Predicate pred) 
{ 
       while (first != last && !pred(*first)) ++first; 
       return first; 
}

template< class InputIt, class UnaryPredicate >
InputIt find_if( InputIt first, InputIt last,
                 UnaryPredicate p );
template< class InputIt, class UnaryPredicate >
constexpr InputIt find_if( InputIt first, InputIt last,
                           UnaryPredicate p );
template< class ExecutionPolicy, class ForwardIt, class UnaryPredicate >
ForwardIt find_if( ExecutionPolicy&& policy, ForwardIt first, ForwardIt last,
                 UnaryPredicate p );

  简单说就是 返回迭代器中first到last之间第一个使得pred函数返回true的 迭代器指针。
所以得自己实现一个比较函数

  一种方式是实现一个类,类内提供一个value_type类型成员变量,实现构造函数,重载operator () --基本上这三个就足够了。如下:

class map_value_finder
{
public:
	map_value_finder(QString &cmp_string):m_s_cmp_string(cmp_string){}
	bool operator ()(const std::map<int, QString>::value_type &pair)
	{
		if ( pair.second.compare(m_s_cmp_string) == 0)
			return true;
		return false;
	}
private:
	const QString &m_s_cmp_string;                    
};

  使用的时候:

std::map<int, QString>::iterator iter = m_mapIndexToFileGuid.end();
iter = std::find_if(m_mapIndexToFileGuid.begin(),
m_mapIndexToFileGuid.end(), map_value_finder(task->pFileInfo->fileID));

  创建一个map_value_finder的临时对象,直接调用其对象的operator()即可。

  如果想要定义模板类型的多类型参数接收的代码,个人愚见如下:

#include <map>
#include <utility>

template<class Key, class Value>
class TzStdMapValueFinder
{
public:
    TzStdMapValueFinder(Key & key, Value & value) : m_key(key), m_value(value)
    {

    }
    bool operator() (const typename std::map<Key, Value>::value_type & sPair)
    {
        if (sPair.second == m_value)
        {
            return true;
        }
        return false;
    }
private:
    const Key & m_key;
    const typename Value& m_value;
};

  上述类在使用的时候类似下面的情况:

void testMap(void) 
{
    std::map<int, QString> mapT;
    for (int i = 0; i < 10; i++)
    {
        mapT[i] = "Number : " + QString::number(i);
    }
    std::map<int, QString>::iterator iter = mapT.end();
    QString str("Number : 1");
    int num = 0;
    TzStdMapValueFinder<int, QString> p(str, num);
    iter = std::find_if(mapT.begin(), mapT.end(), p);
    qDebug() << __FILE__ << __LINE__ << __FUNCDNAME__ << iter->first << iter->second;
}

单独函数专门处理

  或者, 单独一个函数,此函数专门用来查找value_type, 具体情况如下:

QString strGlobal = "D";
bool TestFindValue(const std::map<int,QString>::value_type &pair)
{
    if(pair.second.compare(strGlobal) == 0)
	  return true;
	return false;
}

  调用的时候:

std::map<int, QString>::iterator iter = std::find_if(map_Test.begin(), map_Test.end(), TestFindValue);

  直接传入函数地址即可。这种用法就比较繁琐,使用时需要自己去存储value。

  个人倾向于第一种,网上很多资源也是提供的第一种。另外:std::map 插入的2种方式比较:

  1. insert: map.insert(std::makepair(key,value));
  2. map[key]=value;

  区别:

   1. 第一种方式,遍历map,如果没找到key,则插入,否则不插入。

   2. 第二种方式,如果没找到则插入,否则将对应的key项的值赋给value。

  你可能觉得,第二种方式多好,找不到就插入,比第一种靠谱多了。第二种方式确实更靠谱,但是比起第一种方式,它的代价会更大,这种靠谱是要花时间的。

  尤其在遇到value为对象的情况时,就需要好好考虑了。

   因为第二种方式相当于是:系统先默认构造一个对象,然后给它赋值,最后还要销毁它(3部分时间)。如果用想要的value赋给对象,显然比默认构造一个对象再赋值更高效。这就是insert。

   当对象内属性很多时就更应该考虑了。

   具体insert的返回值,可以再深入了解下,比如插入是否成功。

   返回值为一个pair,pair构成一个迭代器,一个bool变量,bool变量标识是否插入成功,iterator指向插入成功的map元素。

mymap.insert ( std::pair<char,int>('a',100) );
  mymap.insert ( std::pair<char,int>('z',200) );
 
  std::pair<std::map<char,int>::iterator,bool> ret;
  ret = mymap.insert ( std::pair<char,int>('z',500) );
  if (ret.second==false) {
    std::cout << "element 'z' already existed";
    std::cout << " with a value of " << ret.first->second << '\n';
  }