使用STL和一元函数适配仿函数检查列表成员资格

时间:2009-11-20 23:02:40

标签: c++ iterator functor generic-programming stl

我试图编写一个简短的实用程序函数,它接受两个std :: pair项并测试它们的相等性,但忽略了元素的排序。另外(这是我遇到麻烦的地方)我写了一个函数来获取那些std :: pair项的容器并测试容器中给定对参数的成员资格。

/* A quick functor way to check the identity of the two items of a pair to see if each pair contains the same items regardless of order */
template <class T>
class EqualPairs : public std::binary_function<T,T,bool> {
  T arg2;

  public:
  explicit EqualPairs (const T& x) : arg2(x) { }

  bool operator() (const T& arg1) { 
    bool same = false;
    if (arg1 == arg2 || (arg1.first == arg2.second && arg1.second == arg2.first))
      same = true;
    return same;
  }
};

/* checks to see if the give pair p is a member of the list of pairs l. The pairs are compared disregarding the order of the pair elements (i.e. (4,2) == (2,4)) */
template <class P>
bool PairListMember (const P& p, const std::vector<P>& l)
{
  std::vector<P>::iterator it;
  it = find_if (l.begin(), l.end(), EqualPairs<P>(p));
  bool member_of_list = (it != l.end()) ? true : false;
  return member_of_list;
}

我想不出允许通用容器选择的简洁方法,所以我现在硬编码std :: vector作为容器类型。关于使容器类型通用的帮助也将受到赞赏,但是现在我只想让上面的内容进行编译和工作。我得到的错误是:

In function ‘bool PairListMember(const P&, const std::vector<P, std::allocator<_CharT> >&)’:

    error: expected `;' before ‘it’
    error: ‘it’ was not declared in this scope

In function ‘bool PairListMember(const P&, const std::vector<P, std::allocator<_CharT> >&) [with P = std::pair<int, int>]’:

    error: dependent-name ‘std::vector<P,std::allocator<_CharT> >::iterator’ is parsed as a non-type, but instantiation yields a type
    note: say ‘typename std::vector<P,std::allocator<_CharT> >::iterator’ if a type is meant

通过添加建议的'typename'来更改代码只会导致以下错误:

error: no match for ‘operator=’ in ‘it = std::find_if [with _InputIterator = __gnu_cxx::__normal_iterator<const std::pair<int, int>*, std::vector<std::pair<int, int>, std::allocator<std::pair<int, int> > > >, _Predicate = EqualPairs<std::pair<int, int> >](((const std::vector<std::pair<int, int>, std::allocator<std::pair<int, int> > >*)l)->std::vector<_Tp, _Alloc>::begin [with _Tp = std::pair<int, int>, _Alloc = std::allocator<std::pair<int, int> >](), ((const std::vector<std::pair<int, int>, std::allocator<std::pair<int, int> > >*)l)->std::vector<_Tp, _Alloc>::end [with _Tp = std::pair<int, int>, _Alloc = std::allocator<std::pair<int, int> >](), EqualPairs<std::pair<int, int> >(((const std::pair<int, int>&)((const std::pair<int, int>*)p))))’

/usr/include/c++/4.2/bits/stl_iterator.h:637: note: candidates are: __gnu_cxx::__normal_iterator<std::pair<int, int>*, std::vector<std::pair<int, int>, std::allocator<std::pair<int, int> > > >& __gnu_cxx::__normal_iterator<std::pair<int, int>*, std::vector<std::pair<int, int>, std::allocator<std::pair<int, int> > > >::operator=(const __gnu_cxx::__normal_iterator<std::pair<int, int>*, std::vector<std::pair<int, int>, std::allocator<std::pair<int, int> > > >&)

2 个答案:

答案 0 :(得分:5)

对于编译器错误,您需要使用typename关键字。

typename std::vector<P>::iterator it;

iterator是一个typename,即它引用std :: vector中的嵌入类型。在模板中使用::运算符访问类型名时,需要使用typename关键字,以便编译器知道它是类型的名称,而不是类中某些变量或函数的名称。

修改另外,您需要使用const_iterator,因为在这种情况下您的向量是常量。

typename std::vector<P>::const_iterator it;

答案 1 :(得分:3)

您的EqualPairs模板存在一些问题。它派生自binary_function但实际上不是binary_function,因为operator()只接受一个参数。您可以(并且应该)生成operator() const,因为它不会修改EqualPairs对象。

我认为你可以稍微简化它。

template<class T>
struct EqualPairs : public std::binary_function<T, T, bool>
{
    bool operator()(const T& lhs, const T& rhs) const
    {
        return lhs == rhs || lhs.first == rhs.second && lhs.second == rhs.first;
    }
};

然后,您可以使用std::bind1st(或std::bind2nd)从二进制函数和输入参数中生成谓词。此外,通过使函数成为“单一线性”,您实际上不需要为迭代器声明临时变量,因此使consttypename正确不是问题。

template <class P>
bool PairListMember (const P& p, const std::vector<P>& l)
{
    return l.end() != std::find_if(l.begin(), l.end(), std::bind1st(EqualPairs<P>(), p));
}

通过将迭代器类型作为模板参数,可以使此模板更通用。这消除了您对std::vector的依赖。

template <class Iter>
bool PairListMember(const typename std::iterator_traits<Iter>::value_type& p, Iter first, Iter last)
{
    return last != std::find_if(first, last, std::bind1st(EqualPairs<typename std::iterator_traits<Iter>::value_type>(), p));
}