problem on creating functor for std::sort

Discussion in 'C++' started by lok, Dec 1, 2003.

  1. lok

    lok Guest

    i have a class:

    template <class T1, class T2>
    class CPairMapping {
    public:
    typedef std::pair<T1, T2> ValuePair_t;
    typedef std::vector<ValuePair_t> ValueList_t;
    typedef std::binary_function< ValuePair_t, ValuePair_t, bool> ValuePair_IsLess;

    void SortAscend(const ValuePair_IsLess& isLess_) {
    std::sort(Map.begin(), Map.end(), isLess_);
    }

    // skip other funciton like add,delete,lookup...
    protected:
    ValueList_t Map;
    };

    i want to sort the Map with a functor supplied by the caller of SortAscend()


    i created a functor:
    typedef COne2ManyMapping<int, int> INT2INTMap;
    class INT2INTMap_IsLess: public INT2INTMap::ValuePair_IsLess {
    public:
    bool operator() (INT2INTMap::ValuePair_t lhs_,INT2INTMap::ValuePair_t rhs_)
    {
    return true;
    }
    };

    up to now, no compile or link error
    but if i call the SortAscend loke this:
    INT2INTMap a;
    a.AddEntry(1, 2);
    a.AddEntry(3, 4);
    a.SortAscend( INT2INTMap_IsLess() );

    my vc++ 6.0 compiler reported:
    error C2064: term does not evaluate to a function
    see reference to function template instantiation '
    void __cdecl std::_Unguarded_insert(
    struct std::pair<int,int> *,
    struct std::pair<int,int>,
    struct std::binary_function<
    struct std::pair<int,int>,
    struct std::pair<int,int>,
    bool
    >

    )
    ' being compiled

    what is the problem ?
    thx
     
    lok, Dec 1, 2003
    #1
    1. Advertising

  2. lok

    Rolf Magnus Guest

    lok wrote:

    > i have a class:
    >
    > template <class T1, class T2>
    > class CPairMapping {
    > public:
    > typedef std::pair<T1, T2> ValuePair_t;
    > typedef std::vector<ValuePair_t> ValueList_t;
    > typedef std::binary_function< ValuePair_t, ValuePair_t, bool>
    > ValuePair_IsLess;
    >
    > void SortAscend(const ValuePair_IsLess& isLess_) {
    > std::sort(Map.begin(), Map.end(), isLess_);
    > }
    >
    > // skip other funciton like add,delete,lookup...
    > protected:
    > ValueList_t Map;
    > };
    >
    > i want to sort the Map with a functor supplied by the caller of
    > SortAscend()
    >
    >
    > i created a functor:
    > typedef COne2ManyMapping<int, int> INT2INTMap;
    > class INT2INTMap_IsLess: public INT2INTMap::ValuePair_IsLess {
    > public:
    > bool operator() (INT2INTMap::ValuePair_t
    > lhs_,INT2INTMap::ValuePair_t rhs_)
    > {
    > return true;
    > }
    > };
    >
    > up to now, no compile or link error
    > but if i call the SortAscend loke this:
    > INT2INTMap a;
    > a.AddEntry(1, 2);
    > a.AddEntry(3, 4);
    > a.SortAscend( INT2INTMap_IsLess() );
    >
    > my vc++ 6.0 compiler reported:
    > error C2064: term does not evaluate to a function
    > see reference to function template instantiation '
    > void __cdecl std::_Unguarded_insert(
    > struct std::pair<int,int> *,
    > struct std::pair<int,int>,
    > struct std::binary_function<
    > struct std::pair<int,int>,
    > struct std::pair<int,int>,
    > bool
    > >

    > )
    > ' being compiled
    >
    > what is the problem ?


    Your operator() is not const, so it isn't considered when std::sort
    tries to call your function object.
     
    Rolf Magnus, Dec 1, 2003
    #2
    1. Advertising

  3. lok

    lok Guest

    "Rolf Magnus" <> wrote in message
    news:bqfcoh$uhc$02$-online.com...
    > lok wrote:
    >
    > > i have a class:
    > >
    > > template <class T1, class T2>
    > > class CPairMapping {
    > > public:
    > > typedef std::pair<T1, T2> ValuePair_t;
    > > typedef std::vector<ValuePair_t> ValueList_t;
    > > typedef std::binary_function< ValuePair_t, ValuePair_t, bool>
    > > ValuePair_IsLess;
    > >
    > > void SortAscend(const ValuePair_IsLess& isLess_) {
    > > std::sort(Map.begin(), Map.end(), isLess_);
    > > }
    > >
    > > // skip other funciton like add,delete,lookup...
    > > protected:
    > > ValueList_t Map;
    > > };
    > >
    > > i want to sort the Map with a functor supplied by the caller of
    > > SortAscend()
    > >
    > >
    > > i created a functor:
    > > typedef COne2ManyMapping<int, int> INT2INTMap;
    > > class INT2INTMap_IsLess: public INT2INTMap::ValuePair_IsLess {
    > > public:
    > > bool operator() (INT2INTMap::ValuePair_t
    > > lhs_,INT2INTMap::ValuePair_t rhs_)
    > > {
    > > return true;
    > > }
    > > };
    > >
    > > up to now, no compile or link error
    > > but if i call the SortAscend loke this:
    > > INT2INTMap a;
    > > a.AddEntry(1, 2);
    > > a.AddEntry(3, 4);
    > > a.SortAscend( INT2INTMap_IsLess() );
    > >
    > > my vc++ 6.0 compiler reported:
    > > error C2064: term does not evaluate to a function
    > > see reference to function template instantiation '
    > > void __cdecl std::_Unguarded_insert(
    > > struct std::pair<int,int> *,
    > > struct std::pair<int,int>,
    > > struct std::binary_function<
    > > struct std::pair<int,int>,
    > > struct std::pair<int,int>,
    > > bool
    > > >

    > > )
    > > ' being compiled
    > >
    > > what is the problem ?

    >
    > Your operator() is not const, so it isn't considered when std::sort
    > tries to call your function object.
    >


    thx for your rely

    i changed the operator() to this:
    bool operator() (INT2INTMap::ValuePair_t lhs_,INT2INTMap::ValuePair_t rhs_)
    const
    {
    return true;
    }

    the same error still occured
     
    lok, Dec 1, 2003
    #3
  4. lok wrote in news::

    > i have a class:
    >
    > template <class T1, class T2>
    > class CPairMapping {
    > public:
    > typedef std::pair<T1, T2> ValuePair_t;
    > typedef std::vector<ValuePair_t> ValueList_t;
    > typedef std::binary_function< ValuePair_t, ValuePair_t, bool>
    > ValuePair_IsLess;
    >
    > void SortAscend(const ValuePair_IsLess& isLess_) {
    > std::sort(Map.begin(), Map.end(), isLess_);


    This isn't going to work std::binary_function< > isn't a binary function
    its a base class for function object's that *only* supplies some
    typedef's that describe the arguments and return values.

    It does *NOT* have a virtual operator () (T const &, T const &) const.

    You need to pass std::sort() a genuine functor.

    std::less< ValuePair_t >() would be a good start.

    std::sort(Map.begin(), Map.end(), std::less< ValuePair_t >() );


    > }
    >
    > // skip other funciton like add,delete,lookup...
    > protected:
    > ValueList_t Map;
    > };
    >
    > i want to sort the Map with a functor supplied by the caller of
    > SortAscend()
    >


    You can a make SortAscend() a template member function (uppgrade your
    compiler first) or make a functor with a virtual operator () ...


    >
    > i created a functor:
    > typedef COne2ManyMapping<int, int> INT2INTMap;
    > class INT2INTMap_IsLess: public INT2INTMap::ValuePair_IsLess {
    > public:
    > bool operator() (INT2INTMap::ValuePair_t
    > lhs_,INT2INTMap::ValuePair_t rhs_) {
    > return true;
    > }
    > };


    Make operator () a const member, also unless you like writing programmes
    that hang or crash make it a valid Ordering function (model a < b) simply
    returning true is nonsence.

    std::sort(Map.begin(), Map.end(), INT2INTMap_IsLess() );

    >
    > up to now, no compile or link error
    > but if i call the SortAscend loke this:
    > INT2INTMap a;
    > a.AddEntry(1, 2);
    > a.AddEntry(3, 4);
    > a.SortAscend( INT2INTMap_IsLess() );
    >
    > my vc++ 6.0 compiler reported:
    > error C2064: term does not evaluate to a function


    Yup std::binary_function<> isn't a functor.

    > see reference to function template instantiation '
    > void __cdecl std::_Unguarded_insert(
    > struct std::pair<int,int> *,
    > struct std::pair<int,int>,
    > struct std::binary_function<
    > struct std::pair<int,int>,
    > struct std::pair<int,int>,
    > bool
    > >

    > )
    > ' being compiled
    >


    HTH.

    Rob.
    --
    http://www.victim-prime.dsl.pipex.com/
     
    Rob Williscroft, Dec 1, 2003
    #4
  5. lok

    lok Guest

    "Rob Williscroft" <> wrote in message
    news:Xns9444BA3ED6E91ukcoREMOVEfreenetrtw@195.129.110.130...
    > lok wrote in news::
    >
    > > i have a class:
    > >
    > > template <class T1, class T2>
    > > class CPairMapping {
    > > public:
    > > typedef std::pair<T1, T2> ValuePair_t;
    > > typedef std::vector<ValuePair_t> ValueList_t;
    > > typedef std::binary_function< ValuePair_t, ValuePair_t, bool>
    > > ValuePair_IsLess;
    > >
    > > void SortAscend(const ValuePair_IsLess& isLess_) {
    > > std::sort(Map.begin(), Map.end(), isLess_);

    >
    > This isn't going to work std::binary_function< > isn't a binary function
    > its a base class for function object's that *only* supplies some
    > typedef's that describe the arguments and return values.
    >
    > It does *NOT* have a virtual operator () (T const &, T const &) const.
    >
    > You need to pass std::sort() a genuine functor.
    >
    > std::less< ValuePair_t >() would be a good start.
    >
    > std::sort(Map.begin(), Map.end(), std::less< ValuePair_t >() );


    thx for your reply
    i realize the problem (though not completely understand...)
    but i need my own less comparison (that's why i want to create a
    INT2INTMap_IsLess functor)

    >
    >
    > > }
    > >
    > > // skip other funciton like add,delete,lookup...
    > > protected:
    > > ValueList_t Map;
    > > };
    > >
    > > i want to sort the Map with a functor supplied by the caller of
    > > SortAscend()
    > >

    >
    > You can a make SortAscend() a template member function (uppgrade your
    > compiler first) or make a functor with a virtual operator () ...


    i think this is the direction to go
    can u explain further ? thx

    >
    >
    > >
    > > i created a functor:
    > > typedef COne2ManyMapping<int, int> INT2INTMap;
    > > class INT2INTMap_IsLess: public INT2INTMap::ValuePair_IsLess {
    > > public:
    > > bool operator() (INT2INTMap::ValuePair_t
    > > lhs_,INT2INTMap::ValuePair_t rhs_) {
    > > return true;
    > > }
    > > };

    >
    > Make operator () a const member, also unless you like writing programmes
    > that hang or crash make it a valid Ordering function (model a < b) simply
    > returning true is nonsence.


    it just a test code to make the code more simple


    >
    > std::sort(Map.begin(), Map.end(), INT2INTMap_IsLess() );
    >
    > >
    > > up to now, no compile or link error
    > > but if i call the SortAscend loke this:
    > > INT2INTMap a;
    > > a.AddEntry(1, 2);
    > > a.AddEntry(3, 4);
    > > a.SortAscend( INT2INTMap_IsLess() );
    > >
    > > my vc++ 6.0 compiler reported:
    > > error C2064: term does not evaluate to a function

    >
    > Yup std::binary_function<> isn't a functor.
    >
    > > see reference to function template instantiation '
    > > void __cdecl std::_Unguarded_insert(
    > > struct std::pair<int,int> *,
    > > struct std::pair<int,int>,
    > > struct std::binary_function<
    > > struct std::pair<int,int>,
    > > struct std::pair<int,int>,
    > > bool
    > > >

    > > )
    > > ' being compiled
    > >

    >
    > HTH.
    >
    > Rob.
    > --
    > http://www.victim-prime.dsl.pipex.com/
     
    lok, Dec 1, 2003
    #5
  6. lok

    lok Guest

    i modified the code as follow:
    ==================================
    #include <vector>
    #include <functional>
    #include <string>
    using std::string;

    template <class T1, class T2 >
    class CPairMapping {
    public:
    typedef std::pair<T1, T2 > ValuePair_t;
    typedef std::vector<ValuePair_t > ValueList_t;

    class ValuePair_IsLess {
    public:
    virtual bool operator() (const ValuePair_t& lhs_,const ValuePair_t&
    rhs_) const;
    };

    void SortAscend(const ValuePair_IsLess* isLess_) {
    std::sort(Map.begin(), Map.end(), *isLess_);
    }
    protected:
    ValueList_t Map;
    };

    typedef CPairMapping< string, string > STR2STRMap;

    class STR2STRMap_IsLess: public STR2STRMap::ValuePair_IsLess {
    public:
    bool operator() (const STR2STRMap::ValuePair_t& lhs_, const
    STR2STRMap::ValuePair_t& rhs_) const {
    return lhs_.first().size() < rhs_.first().size(); // #error line
    }
    };


    int main() {
    STR2STRMap a;
    STR2STRMap_IsLess isLess;
    a.SortAscend( &isLess );
    return 0;
    }
    ==================================
    now vc compiler reported at #error line:
    error C2064: term does not evaluate to a function
    error C2228: left of '.size' must have class/struct/union type
    error C2064: term does not evaluate to a function
    error C2228: left of '.size' must have class/struct/union type

    it seem compiler doesnt recognize STR2STRMap::ValuePair_t is a pair<
    string, string > object

    how can i solve this error ?
    thx
     
    lok, Dec 2, 2003
    #6
  7. lok wrote in news::

    >
    > i modified the code as follow:
    > ==================================


    Firstly my appologiess, I gave bad advise, makeing operator() virtual
    was not a good idea as functors are mostly passed by value (so that
    an ordinary function is also a functor), so slicing would occur
    and what gets passed to std::sort is the base class with the
    original operator ().

    The following is a fix (of sorts) but it has no real advantage
    over using a simple function pointer. Though it could if you need
    to make the functor more complex.

    #include <vector>
    #include <functional>
    #include <algorithm> // std::sort()
    #include <string>

    using std::string;

    template <class T1, class T2 >
    class CPairMapping
    {
    public:

    typedef std::pair<T1, T2 > ValuePair_t;
    typedef std::vector< ValuePair_t > ValueList_t;

    class ValuePair_IsLess :
    std::binary_function<
    ValuePair_t const &, ValuePair_t const &, bool
    >

    {
    protected:

    typedef
    bool (*m_cmp_t)(
    ValuePair_t const &lhs_, ValuePair_t const & rhs_
    )
    ;
    m_cmp_t m_cmp;

    public:

    ValuePair_IsLess( m_cmp_t cmp ) : m_cmp( cmp ) {}

    bool operator() (
    ValuePair_t const &lhs_, ValuePair_t const &rhs_
    ) const
    {
    return m_cmp( lhs_, rhs_ );
    }
    };

    void SortAscend( ValuePair_IsLess isLess_ )
    {
    std::sort( Map.begin(), Map.end(), isLess_ );
    }

    protected:

    ValueList_t Map;
    };

    typedef CPairMapping< string, string > STR2STRMap;

    class STR2STRMap_IsLess: public STR2STRMap::ValuePair_IsLess
    {
    static bool cmp(
    STR2STRMap::ValuePair_t const &lhs_,
    STR2STRMap::ValuePair_t const &rhs_
    )
    {
    return lhs_.first.size() < rhs_.first.size(); // #error line

    // note the lack of .first().size() ..


    }

    typedef STR2STRMap::ValuePair_IsLess base_t;

    public:

    STR2STRMap_IsLess() : base_t( cmp ) {}
    };


    int main()
    {
    STR2STRMap a;
    STR2STRMap_IsLess isLess;
    a.SortAscend( isLess );
    return 0;
    }


    Here's a simple function version, there is *alot* less cruft if
    you really don't need it.


    #include <vector>
    #include <functional>
    #include <algorithm> // std::sort()
    #include <string>

    using std::string;

    template <class T1, class T2 >
    class CPairMapping
    {
    public:

    typedef std::pair<T1, T2 > ValuePair_t;
    typedef std::vector< ValuePair_t > ValueList_t;

    typedef bool (*ValuePair_IsLess)(
    ValuePair_t const &lhs_, ValuePair_t const & rhs_
    );

    void SortAscend( ValuePair_IsLess isLess_ )
    {
    std::sort( Map.begin(), Map.end(), isLess_ );
    }

    protected:

    ValueList_t Map;
    };

    typedef CPairMapping< string, string > STR2STRMap;

    bool STR2STRMap_IsLess(
    STR2STRMap::ValuePair_t const &lhs_,
    STR2STRMap::ValuePair_t const & rhs_
    )
    {
    return lhs_.first.size() < rhs_.first.size();
    }

    int main()
    {
    STR2STRMap a;
    //STR2STRMap_IsLess isLess;
    a.SortAscend( STR2STRMap_IsLess );
    return 0;
    }

    Rob.
    --
    http://www.victim-prime.dsl.pipex.com/
     
    Rob Williscroft, Dec 2, 2003
    #7
  8. lok

    lok Guest

    after some little modification,
    no compile, link or runtime error now
    the code are follow:
    =====================
    #include <vector>
    #include <functional>
    #include <string>
    using std::string;

    template <class T1, class T2 >
    class CPairMapping {
    public:
    typedef std::pair<T1, T2 > ValuePair_t;
    typedef std::vector<ValuePair_t > ValueList_t;

    class ValuePair_IsLess {
    public:
    virtual bool operator() (const ValuePair_t& lhs_,const ValuePair_t&
    rhs_) const {
    return lhs_ < rhs_;
    }
    };

    void SortAscend(const ValuePair_IsLess& isLess_) {
    std::sort(Map.begin(), Map.end(), isLess_);
    }
    protected:
    ValueList_t Map;
    };

    typedef CPairMapping< string, string > STR2STRMap;

    class STR2STRMap_IsLess: public STR2STRMap::ValuePair_IsLess {
    public:
    bool operator() (const STR2STRMap::ValuePair_t& lhs_, const
    STR2STRMap::ValuePair_t& rhs_) const {
    return lhs_.first.size() < rhs_.first.size();
    }
    };

    int main() {
    STR2STRMap a;
    STR2STRMap_IsLess isLess;
    a.SortAscend( &isLess );
    }
    =====================
    but in debug mode, i found std::sort called the operator() of
    CPairMapping::ValuePair_IsLess instead of the operator() of
    STR2STRMap_IsLess
    it seem the dynamic binding of virtual function failed to work
    is this because a new CPairMapping::ValuePair_IsLess is created to
    pass to the std::sort funciton ?

    how to solve this problem ?

    thx
     
    lok, Dec 2, 2003
    #8
  9. lok wrote in news::

    > after some little modification,
    > no compile, link or runtime error now
    > the code are follow:

    [snip]
    > but in debug mode, i found std::sort called the operator() of
    > CPairMapping::ValuePair_IsLess instead of the operator() of
    > STR2STRMap_IsLess
    > it seem the dynamic binding of virtual function failed to work
    > is this because a new CPairMapping::ValuePair_IsLess is created to
    > pass to the std::sort funciton ?
    >
    > how to solve this problem ?
    >


    This works on the 3 conpilers I tried, (unfortunatly I haven't got
    VC++ 6.0). See the comments inline:

    #include <vector>
    #include <functional>
    #include <algorithm> /* forgot this again (std::sort) */
    #include <string>
    #include <iostream>

    using std::string;

    template <class T1, class T2 >
    class CPairMapping
    {
    public:

    typedef std::pair<T1, T2 > ValuePair_t;
    typedef std::vector<ValuePair_t > ValueList_t;
    typedef typename std::vector<ValuePair_t >::iterator iterator;


    class ValuePair_IsLess
    {
    public:
    virtual bool operator() (
    const ValuePair_t& lhs_,const ValuePair_t& rhs_
    ) const
    {
    return lhs_ < rhs_;
    }
    };

    void SortAscend(const ValuePair_IsLess& isLess_)
    {
    /* This is the trick,
    force std::sort to take a Comparitor by reference
    */
    std::sort<
    iterator, ValuePair_IsLess const &
    >(

    Map.begin(), Map.end(), isLess_
    )
    ;
    }

    void add( T1 const &a, T2 const &b )
    {
    Map.push_back( ValuePair_t( a, b ) );
    }

    iterator begin() { return Map.begin(); }
    iterator end() { return Map.end(); }

    protected:

    ValueList_t Map;
    };


    typedef CPairMapping< string, string > STR2STRMap;

    class STR2STRMap_IsLess: public STR2STRMap::ValuePair_IsLess
    {
    public:
    bool operator() (
    const STR2STRMap::ValuePair_t& lhs_,
    const STR2STRMap::ValuePair_t& rhs_
    ) const
    {
    return lhs_.first.size() < rhs_.first.size();
    }
    };


    template < typename Iterator >
    std::eek:stream &print_pairs( std::eek:stream &os, Iterator ptr, Iterator lim
    )
    {

    if ( ptr != lim ) for (;;)
    {
    os << "( " << ptr->first << ", " << ptr->second << " )";
    if (++ptr == lim ) break;
    os << ", ";
    }
    return os;
    }


    int main()
    {
    STR2STRMap a;
    STR2STRMap_IsLess isLess;

    a.add( "2", "a" );
    a.add( "1", "b" );

    print_pairs( std::cerr, a.begin(), a.end() ) << "\n";

    a.SortAscend( isLess ); /* pass by ref */

    print_pairs( std::cerr, a.begin(), a.end() ) << "\n";
    }




    Rob.
    --
    http://www.victim-prime.dsl.pipex.com/
     
    Rob Williscroft, Dec 2, 2003
    #9
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Tanguy Fautré
    Replies:
    3
    Views:
    2,774
    Tanguy Fautré
    Dec 2, 2003
  2. Joel
    Replies:
    2
    Views:
    819
  3. news.online.no
    Replies:
    2
    Views:
    528
    Daniel T.
    Jan 30, 2006
  4. Replies:
    1
    Views:
    503
    Marcus Kwok
    Apr 6, 2007
  5. Fei Liu
    Replies:
    5
    Views:
    400
    Fei Liu
    Aug 21, 2007
Loading...

Share This Page