Predicate Member Function



  • Hallo,
    ich möchte bei std::remove_if dem dritten Paramter mit einer Member-Function belegen.
    Ich habe schon herumprobiert und von Lösungen mit std::mem_fun und std::bind1st/std::bind2nd gelesen, aber bisher hat nichts funktioniert.
    Könnte mir jemand zeigen, wie es richtig geht?

    Eine minimalisierte Version:

    class Foo
    {
    public:
    	void call_me();
    	template <int N> bool mfunction(int i);
    	std::vector<int> container;
    };
    
    template <int N> 
    bool mfunction(int i)
    {
    	return N > i;
    }
    
    void Foo::call_me()
    {
    	std::remove_if(container.begin(), container.end(), &Foo::mfunction<5>);
    }
    
    int _tmain(int argc, _TCHAR* argv[])
    {
    	Foo x;
    	x.call_me();
    	return 0;
    }
    

    Compilerfehler:

    d:\programme\microsoft visual studio 10.0\vc\include\algorithm(1839): error C2064: Ausdruck ergibt keine Funktion, die 1 Argumente übernimmt
    1> d:\programme\microsoft visual studio 10.0\vc\include\algorithm(1853): Siehe Verweis auf die Instanziierung der gerade kompilierten Funktions-template "_FwdIt std::_Remove_if<int*,_Pr>(_FwdIt,_FwdIt,_Pr)".
    1> with
    1> [
    1> _FwdIt=int ,
    1> _Pr=bool (__thiscall Foo::
    )(int)
    1> ]
    1> c:\users\wurst\documents\visual studio 2010\projects\testasdf\testasdf\testasdf.cpp(20): Siehe Verweis auf die Instanziierung der gerade kompilierten Funktions-template "_FwdIt std::remove_if<std::_Vector_iterator<_Myvec>,bool(__thiscall Foo::* )(int)>(_FwdIt,_FwdIt,_Pr)".
    1> with
    1> [
    1> _FwdIt=std::_Vector_iterator<std::_Vector_val<int,std::allocator<int>>>,
    1> _Myvec=std::_Vector_val<int,std::allocator<int>>,
    1> _Pr=bool (__thiscall Foo::* )(int)
    1> ]
    1>



  • Lösung für C++98/03

    #include <vector>
    #include <algorithm>
    #include <functional>
    
    class Foo
    {
    public:
        void call_me();
        template <int N> bool mfunction(int i);
        std::vector<int> container;
    };
    
    void Foo::call_me()
    {
        std::remove_if(container.begin(), container.end(), std::bind1st(std::mem_fun(&Foo::mfunction<5>), this));
    }
    
    template <int N>
    bool Foo::mfunction(int i)
    {
        return N > i;
    }
    
    int main()
    {
        Foo x;
        x.call_me();
        return 0;
    }
    

    Lösung für C++11

    #include <vector>
    #include <algorithm>
    #include <functional>
    
    class Foo
    {
    public:
        void call_me();
        template <int N> bool mfunction(int i);
        std::vector<int> container;
    };
    
    void Foo::call_me()
    {
        std::remove_if(container.begin(), container.end(), std::bind(&Foo::mfunction<5>, this, std::placeholders::_1));
    }
    
    template <int N>
    bool Foo::mfunction(int i)
    {
        return N > i;
    }
    
    int main()
    {
        Foo x;
        x.call_me();
        return 0;
    }
    

    Beide Codes kompilieren mit GCC 4.7.1 und clang 3.2



  • std::remove_if(container.begin(), container.end(), [this] (int i) { return mfunction<5>(i); });
    


  • C++11 hab ich leider nicht 🙂

    Die Lösung von pyhax hatte ich bereits probiert, was im richtigen Code einen Fehler verursacht. Weitere Google-Nachforschungen haben mir die Ursache genannt:
    bind1st mag keine Referenzen als Parameter.

    Das Minimalbeispiel hätte also eher so aussehen müssen:

    class Foo
    {
    public:
    	void call_me();
    	template <int N> bool mfunction(const int& i);
    	std::vector<int> container;
    };
    
    template <int N> 
    bool Foo::mfunction(const int& i)
    {
    	return N > i;
    }
    
    void Foo::call_me()
    {
    	std::remove_if(container.begin(), container.end(), std::bind1st(std::mem_fun(&Foo::mfunction<5>), this));
    }
    
    int _tmain(int argc, _TCHAR* argv[])
    {
    	Foo x;
    	x.call_me();
    	return 0;
    }
    

    Gibt es dafür auch eine Lösung oder muss ich call by value in Kauf nehmen?



  • Nimm boost::function als Zwischenlösung, das funktioniert gleich wie std::function .



  • Nimm boost.bind und dann die c++11 Lösung (mit boost::bind statt std::bind + andere Placeholder namen)



  • VS2010 müsste doch ein std::tr1::bind haben.



  • Stimmt, bind() ist offensichtlich im TR1 auch in VS2010 enthalten. Damit kann ich doch die "C++11"-Lösung nehmen.

    Danke für die Antworten 😃



  • VS2010 hat doch schon std::bind...


Anmelden zum Antworten