【问题标题】:Error with a predicate in std::remove_ifstd::remove_if 中的谓词出错
【发布时间】:2017-03-01 14:55:06
【问题描述】:

我基本上有一个std::deque 的对象,我想根据对象的给定成员变量的条件删除其中一些对象,以便我使用谓词,但我有我没有的错误真懂。

出于 STL 原因(共享指针),我正在使用 g++-std=c++11,但我试图在带有非 c++11 代码的 MVS 的 Windows 上解决这个问题,所以我正在寻找一个非 @987654325 @ 解决方案,没有 lamdas 等

代码是:

#include <iostream> // for std::cout and std::endl
#include <cstdio> // for getchar()
#include <memory> // for std::shared_ptr
#include <deque> // for std::deque
#include <algorithm> // for std::earse and std::remove_if

class A
{
    private:
        int _i;
        double _d;
    public:
        A(int i, double d)
        {
            _i = i;
            _d = d;
        }
        int geti()const
        {
            return _i;
        }
        double getValueOnWhichToCheck()const
        {
            return _d;
        }
};

typedef std::shared_ptr<A> A_shared_ptr;
typedef std::deque<A_shared_ptr> list_type;

void PrintDeque(list_type & dq)
{
    if (0 ==  dq.size())
    {
        std::cout << "Empty deque." << std::endl;
    }
    else
    {
        for (int i = 0 ; i < dq.size() ; ++i)
        {
            std::cout << i+1 << "\t" << dq[i] << std::endl;
        }
    }
}

class B
{
    public:
        double getThreshold() // Non constant for a reason as in real code it isn't
        {
            return 24.987; // comes from a calculation not needed here so I return a constant.
        }
        bool Predicate(A_shared_ptr & a)
        {
            return a->getValueOnWhichToCheck() >= getThreshold();
        }
        void DoStuff()
        {
            A_shared_ptr pT1 = std::make_shared<A>(A(2,      -6.899987));
            A_shared_ptr pT2 = std::make_shared<A>(A(876,    889.878762));
            A_shared_ptr pT3 = std::make_shared<A>(A(-24,    48.98924));
            A_shared_ptr pT4 = std::make_shared<A>(A(78,     -6654.98980));
            A_shared_ptr pT5 = std::make_shared<A>(A(6752,   3.141594209));
            list_type dq = {pT1,pT2,pT3,pT4,pT5};
            PrintDeque(dq);
            bool (B::*PtrToPredicate)(A_shared_ptr &) = &B::Predicate;
            dq.erase(std::remove_if(dq.begin(), dq.end(), PtrToPredicate),dq.end());
            PrintDeque(dq);
        }
};

int main()
{
    B * pB = new B();
    pB->DoStuff();
    getchar();
}

g++ -std=c++11 main.cpp -o main 的输出是:

In file included from /usr/include/c++/5/bits/stl_algobase.h:71:0,
                 from /usr/include/c++/5/bits/char_traits.h:39,
                 from /usr/include/c++/5/ios:40,
                 from /usr/include/c++/5/ostream:38,
                 from /usr/include/c++/5/iostream:39,
                 from main.cpp:1:
/usr/include/c++/5/bits/predefined_ops.h: In instantiation of ‘bool __gnu_cxx::__ops::_Iter_pred<_Predicate>::operator()(_Iterator) [with _Iterator = std::_Deque_iterator<std::shared_ptr<A>, std::shared_ptr<A>&, std::shared_ptr<A>*>; _Predicate = bool (B::*)(std::shared_ptr<A>&)]’:
/usr/include/c++/5/bits/stl_algo.h:866:20:   required from ‘_ForwardIterator std::__remove_if(_ForwardIterator, _ForwardIterator, _Predicate) [with _ForwardIterator = std::_Deque_iterator<std::shared_ptr<A>, std::shared_ptr<A>&, std::shared_ptr<A>*>; _Predicate = __gnu_cxx::__ops::_Iter_pred<bool (B::*)(std::shared_ptr<A>&)>]’
/usr/include/c++/5/bits/stl_algo.h:936:30:   required from ‘_FIter std::remove_if(_FIter, _FIter, _Predicate) [with _FIter = std::_Deque_iterator<std::shared_ptr<A>, std::shared_ptr<A>&, std::shared_ptr<A>*>; _Predicate = bool (B::*)(std::shared_ptr<A>&)]’
main.cpp:67:73:   required from here
/usr/include/c++/5/bits/predefined_ops.h:234:30: error: must use ‘.*’ or ‘->*’ to call pointer-to-member function in ‘((__gnu_cxx::__ops::_Iter_pred<bool (B::*)(std::shared_ptr<A>&)>*)this)->__gnu_cxx::__ops::_Iter_pred<bool (B::*)(std::shared_ptr<A>&)>::_M_pred (...)’, e.g. ‘(... ->* ((__gnu_cxx::__ops::_Iter_pred<bool (B::*)(std::shared_ptr<A>&)>*)this)->__gnu_cxx::__ops::_Iter_pred<bool (B::*)(std::shared_ptr<A>&)>::_M_pred) (...)’
  { return bool(_M_pred(*__it)); }
                              ^

【问题讨论】:

    标签: c++ stl deque


    【解决方案1】:

    您将无法将非静态成员函数指针与remove_if 一起使用。 remove_if 需要普通函数指针、静态成员函数指针或函数对象。它不能使用成员函数指针的原因是它需要一个类的实例才能调用该函数,而您不能将其包装到调用中

    您要么需要创建Predicate static,创建一个函数对象并传递它的一个实例,要么在调用站点中使用一个lambda。

    【讨论】:

    • 我可以使用bind吗? (我真的不是专家,抱歉)
    • @user10000100_u 是的,您可以使用绑定,但这是 C++11 的一项功能,如果您打算使用 C++11,您应该只使用 lambda。
    • 我终于使用了“允许”的boost::bind。无论如何谢谢!
    【解决方案2】:

    不喜欢函数指针,但使用 lambda 的 this 似乎可以编译...https://ideone.com/0StRcw

            dq.erase(std::remove_if(dq.begin(), dq.end(), [this](const std::shared_ptr<A>& a) {
                return a->getValueOnWhichToCheck() >= getThreshold();
            }),dq.end());
    

    或者没有 lambdas..

            auto predicateToUse = std::bind(&B::Predicate, this, std::placeholders::_1);
            dq.erase(std::remove_if(dq.begin(), dq.end(), predicateToUse), dq.end());
    

    不自动更新:

    dq.erase(std::remove_if(dq.begin(), dq.end(), std::bind(&B::Predicate, this, std::placeholders::_1)), dq.end());
    

    【讨论】:

    • 我知道,但我不允许(在我正在使用的解决方案中)使用 lambda 的... :-( 问题已更新
    • 嗯,你有一个共享指针的双端队列,你的谓词引用一个对象,所以你必须改变它来引用一个 shared_ptr
    • 如果你不能使用 lambda,你可以使用基于结构的仿函数吗?
    • 当然可以。试过bool Predicate(A_shared_ptr a) 但我有cannot convert ‘bool (B::*)(A_shared_ptr) {aka bool (B::*)(std::shared_ptr&lt;A&gt;)}’ to ‘bool (B::*)(A_shared_ptr&amp;) {aka bool (B::*)(std::shared_ptr&lt;A&gt;&amp;)}’ in initialization bool (B::*PtrToPredicate)(A_shared_ptr &amp;) = &amp;B::Predicate; 问题...
    • 问题是,正如@NathanOliver 指出的那样,您不能将非静态成员函数指针与remove_if 一起使用。我更新了我的答案以包含使用 std::bind 的各种解决方法,但 lambda 更清晰 imo。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-12-11
    • 1970-01-01
    • 2016-12-14
    • 1970-01-01
    • 2011-09-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多