How do I negate a find_if condition properly?

Discussion in 'C++' started by dave_if, Jul 27, 2005.

  1. dave_if

    dave_if Guest

    I have a vector of TCard objects, I am sorting them based on the the
    box field. That part works fine (finally!). I would then like to
    random_shuffle all cards that are in a particular box, that is, I would
    find the first card that is in box 3, then the first one after that
    which isn't in box 3, and random_shuffle that range instead of the
    usual begin(), end(). For the "not in box 3," I kept trying to use the
    not1 function but I couldn't get anything that would compile. So I
    ended up with (attempt #11):

    class FindIfBox
    {
    public:
    FindIfBox(int box): m_box(box) {}
    int GetBox() { return m_box; }
    bool operator() (const TCard& card) const
    private:
    int m_box;
    };
    //...
    bool FindIfBox::eek:perator() (const TCard& card) const
    {
    // will have to be rewritten for Box 0
    if (this->m_box >= 0)
    return card.m_box == this->m_box;
    else
    return !(card.m_box == this->m_box);
    }
    //...
    vector<TCard>::iterator boxBegin, boxEnd;

    // the sort works perfectly
    // not showing InLesserBox function object
    stable_sort(v.begin(), v.end(), InLesserBox());

    boxBegin = find_if(v.begin(), v.end(), FindIfBox(3));
    boxEnd = find_if(boxBegin, v.end(), FindIfBox(-3));

    //... (print vector)
    // try to shuffle cards with that have box = 3
    random_shuffle(boxBegin, boxEnd);

    //.. (print vector - and it hasn't changed)
    // by the way there are some elements after the box 3 that are in box 4

    It took me two weeks to get something that would compile. I obviously
    have some logic error because the vector doesn't change after the
    shuffle. Maybe I have a temporary going out of scope somewhere, that's
    what it usually is, right? Or a missing &.

    I wanted to be able to say (and this doesn't compile)
    boxEnd = find_if(boxBegin, v.end(), not1(FindIfBox(3));

    Is there a way to say something like that using valid C++ so I don't
    have to junk up my operator() member function in the FindInBox object?
    dave_if, Jul 27, 2005
    #1
    1. Advertising

  2. dave_if wrote:
    > class FindIfBox
    > {
    > public:
    > FindIfBox(int box): m_box(box) {}
    > int GetBox() { return m_box; }
    > bool operator() (const TCard& card) const
    > private:
    > int m_box;
    > };


    According to the requirements for unary functions, this is not a
    unary in the sense of STL. Unfortunately, I don't think that the
    standard really spells out the requirements for unary functions
    explicitly. Essentially, if 'UF' is unary function type, 'uf' is
    an object thereof, 'A' is the argument type, 'a' an object thereof,
    and 'R' the result type, the following shall be legal;

    Expression Type Semantic
    UF::argument_type A type of the argument
    UF::result_type R type returned by the function call
    uf(a) R function call

    Effectively, these requirements turn normal functions into useless
    function objects if they are indeed imposed. Many algorithms and
    uses of function object have relaxed requirements which do not
    need the associated types. However, the current function adaptors
    normally do have these requirements which is the reason why you
    you have to use 'ptr_fun()', 'mem_fun()', etc. if you want to
    adapt normal functions.

    The following program compiled fine for me and I'm confident that
    it does what you want it to do:

    #include <iostream>
    #include <string>
    #include <vector>
    #include <functional>
    #include <algorithm>


    struct TCard
    {
    int m_box;
    };

    class FindIfBox
    {
    public:
    typedef TCard argument_type;
    typedef bool result_type;

    FindIfBox(int box): m_box(box) {}
    int GetBox() { return m_box; }
    bool operator() (const TCard& card) const
    {
    return this->m_box == card.m_box;
    }
    private:
    int m_box;
    };

    int main()
    {
    std::vector<TCard> v;

    std::vector<TCard>::iterator boxBegin
    = std::find_if(v.begin(), v.end(), FindIfBox(3));
    std::vector<TCard>::iterator boxEnd
    = std::find_if(boxBegin, v.end(), std::not1(FindIfBox(3)));
    }
    --
    <mailto:> <http://www.dietmar-kuehl.de/>
    <http://www.eai-systems.com> - Efficient Artificial Intelligence
    Dietmar Kuehl, Jul 27, 2005
    #2
    1. Advertising

  3. dave_if

    Alan Johnson Guest

    Dietmar Kuehl wrote:
    [only relevant part quoted]
    > According to the requirements for unary functions, this is not a
    > unary in the sense of STL. Unfortunately, I don't think that the
    > standard really spells out the requirements for unary functions
    > explicitly. Essentially, if 'UF' is unary function type, 'uf' is
    > an object thereof, 'A' is the argument type, 'a' an object thereof,
    > and 'R' the result type, the following shall be legal;
    >
    > Expression Type Semantic
    > UF::argument_type A type of the argument
    > UF::result_type R type returned by the function call
    > uf(a) R function call
    >
    > Effectively, these requirements turn normal functions into useless
    > function objects if they are indeed imposed.


    The standard provides a mechanism for dealing with this in <functional>
    called std::ptr_fun, which returns an object of type
    std::pointer_to_unary_function. So if you have a function, example --

    int sqr(int x) { return x*x ; }

    -- you could adapt it to meet the requirements of a unary function with
    std::ptr_fun(sqr).

    -Alan
    Alan Johnson, Jul 27, 2005
    #3
  4. dave_if

    Csaba Guest

    "dave_if" <> wrote in news:1122437830.358564.54390
    @o13g2000cwo.googlegroups.com:

    > I have a vector of TCard objects, I am sorting them based on the the
    > box field. That part works fine (finally!). I would then like to
    > random_shuffle all cards that are in a particular box, that is, I would
    > find the first card that is in box 3, then the first one after that
    > which isn't in box 3, and random_shuffle that range instead of the
    > usual begin(), end(). For the "not in box 3," I kept trying to use the
    > not1 function but I couldn't get anything that would compile. So I
    > ended up with (attempt #11):
    >
    > class FindIfBox
    > {
    > public:
    > FindIfBox(int box): m_box(box) {}
    > int GetBox() { return m_box; }
    > bool operator() (const TCard& card) const
    > private:
    > int m_box;
    > };

    [snip]
    >
    > I wanted to be able to say (and this doesn't compile)
    > boxEnd = find_if(boxBegin, v.end(), not1(FindIfBox(3));
    >
    > Is there a way to say something like that using valid C++ so I don't
    > have to junk up my operator() member function in the FindInBox object?
    >


    Try deriving FindIfBox from std::unary_function< TCard, bool >, like this:

    struct TCard
    {
    int m_box;
    };

    struct InLesserBox : public std::binary_function< TCard, TCard, bool >
    {
    bool operator()(const TCard& card1, const TCard& card2) const
    {
    return card1.m_box < card2.m_box; // for example
    }
    };

    struct FindIfBox : public std::unary_function< TCard, bool >
    {
    FindIfBox(int box) : m_box(box) {} // as before
    bool operator()(const TCard& card) const
    { return m_box == card.m_box; }
    private:
    int m_box;
    };


    int main(int argc, char* argv[])
    {
    std::vector<TCard> v;
    std::vector<TCard>::iterator boxBegin, boxEnd;

    // the sort works perfectly
    // not showing InLesserBox function object
    stable_sort(v.begin(), v.end(), InLesserBox());

    boxBegin = find_if(v.begin(), v.end(), FindIfBox(3));
    boxEnd = find_if(boxBegin, v.end(), not1(FindIfBox(3)));
    // note number of )))
    //boxEnd = find_if(boxBegin, v.end(), FindIfBox(-3));

    //... (print vector)
    // try to shuffle cards with that have box = 3
    random_shuffle(boxBegin, boxEnd);

    //.. (print vector - and it hasn't changed)
    // by the way there are some elements after the box 3 that are in box 4

    return 0;
    }


    Technically, FindIfBox is a binary_function< TCard, int, bool > and you
    should use it with bind2nd, but a unary_function with a constructor is
    simpler.

    // Note: no constructor, no member variable
    struct FindIfBox2 : public std::binary_function< TCard, int, bool >
    {
    bool operator()(const TCard& card, int box) const
    { return box == card.m_box; }
    };

    boxEnd = find_if( boxBegin, v.end(),
    std::not1( std::bind2nd( FindIfBox2(), 3 ) )
    );

    --
    Life is complex, with real and imaginary parts.
    Csaba, Jul 27, 2005
    #4
  5. dave_if

    dave_if Guest

    Thanks, Dietmar! What a difference those typedefs make! I remember
    seeing that in Bjarne's C++PL book but I didn't know those were
    actually required. So this is the solution I decided to use, because I
    put those 2 typedefs in and fixed the function object and now I can do
    what I want.

    Csaba, I'll look closely at your code too. I tried to use the bind2nd
    function before, but without properly deriving my FindIfBox from
    binary_function<>. I remember reading dire warnings from Bjarne saying
    to use those unary_function and binary_function templates or else
    learn the hard way why they are important, but I couldn't figure out
    how to use them, and I couldn't find any sample code other than
    Bjarne's that used them.

    Thanks Alan for your insights too. At one time I had a FindIfBox
    function as part of the TCard class, I never could get the mem_fun or
    mem_fun_ref to work either. Probably need to spend a few bucks and get
    Josuttis' book, but I'm postponing it as long as I can!
    dave_if, Jul 27, 2005
    #5
  6. dave_if

    dave_if Guest

    Csaba, in rereading my note to you, I meant to put a "Thanks" there
    also!
    dave_if, Jul 27, 2005
    #6
    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. -
    Replies:
    12
    Views:
    686
    Remon van Vliet
    Jun 15, 2005
  2. Rob Mitchell

    [Q] fast way to negate?

    Rob Mitchell, Dec 13, 2005, in forum: Java
    Replies:
    0
    Views:
    357
    Rob Mitchell
    Dec 13, 2005
  3. Replies:
    3
    Views:
    552
    Paul McGuire
    Jan 9, 2005
  4. negate INT_MIN

    , Feb 10, 2007, in forum: C Programming
    Replies:
    2
    Views:
    406
    ┬Ča\\/b
    Feb 10, 2007
  5. Bill W.
    Replies:
    13
    Views:
    289
    Phillip Gawlowski
    May 9, 2011
Loading...

Share This Page