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

发布于 2024-08-12 04:25:43 字数 3395 浏览 6 评论 0原文

我尝试编写一个简短的实用函子,它接受两个 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> > > >&)

I've attempted to write a brief utility functor that takes two std::pair items and tests for their equality, but disregarding the ordering of the elements. Additionally (and this is where I run into trouble) I've written a function to take a container of those std::pair items and test for membership of a given pair argument in a the container.

/* 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;
}

I couldn't think of a clean way to allow for generic container selection, so I hard-coded a std::vector as the container type, for now. Help on making the container type generic would also be appreciated, but for now I'd just like to get the above to compile and work. The error I get is:

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

changing the code by adding a 'typename' as suggested only results in the following errors:

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> > > >&)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

走走停停 2024-08-19 04:25:43

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

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

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

编辑:此外,您需要使用const_iterator,因为在这种情况下您的向量是const。

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

For your compiler error, you need to use the typename keyword.

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

iterator is a typename, i.e. it refers to an embedded type within std::vector. When you access a typename with the :: operator within a template, you need to use the typename keyword so the compiler knows it is the name of a type, as opposed to the name of some variable or function within the class.

Edit: Also, you need to use a const_iterator, because your vector is const in this case.

typename std::vector<P>::const_iterator it;
山有枢 2024-08-19 04:25:43

您的 EqualPairs 模板存在一些问题。它派生自binary_function,但实际上并不是一个binary_function,因为operator() 仅接受一个参数。您可以(并且应该)将 operator() 设置为常量,因为它不会修改 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));
}

There are a couple of issues with your EqualPairs template. It derives from binary_function but isn't actually a binary_function because operator() only takes one argument. You can (and should) make operator() const as it doesn't modify the EqualPairs object.

I think that you can simplify it somewhat.

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;
    }
};

Then you can use std::bind1st (or std::bind2nd) to make a predicate out of your binary function and the input parameter. Also, by making the function a 'one liner' you don't actually need to declare a temporary variable for the iterator, so getting const and typename correct isn't an issue.

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));
}

You can make this template more generic by taking an iterator type as a template parameter. This removes your dependency on 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));
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文