Topic: STL, function objects as parameters


Author: Matthias Lang <zepamlg@zepa.zericsson.zse>
Date: 1997/10/02
Raw View
Owen L. Astrachan wrote:
>
> I want to pass a function object to a method that will call
> STL sort.  Here's a cut-down version of the code I want,
> only relevant methods/classes shown.
>
> class Compare
> {
>   public:
>     virtual bool operator() (const DirEntry & lhs,
>                              const DirEntry & rhs) = 0;
> };
[a few lines cut]

>     ::sort(myEntries.begin(),myEntries.end(),comp);  // STL sort

> In the client program I'm deriving function objects
> from Compare and passing them to the Scandir::sort function.

[more lines cut]

> is the function object template parameter to sort and other STL
> algorithms the only way this is done?  Is there a way I can pass a
> function object to a routine which then forwards the object to sort or
> must all function objects to sort be bound at compile time?

How about adding

bool Compare::operator() ( const DirEntry&lhs, const DirEntry& rhs)
{
 return this->operator()( lhs, rhs);
}

That way the compiler's happy, your Compare class is still abstract
and you get the () operator of your derived class called.

Matthias
Not speaking for Ericsson. Not one 'z' exists in my real email address.
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: Matthias Lang <zepamlg@zepa.zericsson.zse>
Date: 1997/10/03
Raw View
In response to a post asking why it isn't possible to use a
vritual operator() in compare functor used as the third parameter to an
STL class, I wrote

> How about adding
>
> bool Compare::operator() ( const DirEntry&lhs, const DirEntry& rhs)
> {
>         return this->operator()( lhs, rhs);
> }

This seemed like a good idea until I tried it... sort() is defined

 template<class RandomAccessIterator, class Compare>
 void sort(RandomAccessIterator first,
  RandomAccessIterator last,
  Compare comp);

i.e. the Compare functor is passed by value. One way out is
to fall back to putting a pointer to another object which you
use to do the actual comparison in Compare, a rather long
version of which has already been posted by someone else.

Why doesn't sort() pass the compare functor around by reference?.

Matthias
Still not speaking for Ericsson
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: Matt Austern <austern@isolde.mti.sgi.com>
Date: 1997/10/06
Raw View
Matthias Lang <zepamlg@zepa.zericsson.zse> writes:

> i.e. the Compare functor is passed by value. One way out is
> to fall back to putting a pointer to another object which you
> use to do the actual comparison in Compare, a rather long
> version of which has already been posted by someone else.
>
> Why doesn't sort() pass the compare functor around by reference?.

Because if it were passed by mutable reference then you wouldn't
be able to do something like
   sort(first, last, greater<int>()),
and if it were passed by const reference then you wouldn't be able to
use function objects where operator() isn't a const member function.
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: Gerard Weatherby <gerardw@alum.mit.edu>
Date: 1997/09/30
Raw View
Owen L. Astrachan wrote:
>
> I want to pass a function object to a method that will call
> STL sort.  Here's a cut-down version of the code I want,
> only relevant methods/classes shown.
>
> class Compare
> {
>   public:
>     virtual bool operator() (const DirEntry & lhs,
>                              const DirEntry & rhs) = 0;
> };
>
> class Scandir
> {
>   public:
>     Scandir();
>     void sort(Compare & comp);
>   private:
>     vector<DirEntry> myEntries;
> };
>
> void Scandir::sort(Compare & comp)
> {
>     ::sort(myEntries.begin(),myEntries.end(),comp);  // STL sort
> }
> -------
> In the client program I'm deriving function objects
> from Compare and passing them to the Scandir::sort function.
>
> Problems:
>
> However, the third "parameter" to sort is really a template
> argument, and is thus bound at compile time rather than runtime,
> I'm using the SGI STL implementation with a patched cygnus/g++
> on a Sun/Solaris machine.
>
> Also, I must supply a definition for Compare::operator() even though I
> want it to be abstract (but the templated use of it precludes it being
> "really abstract"), and this definition is bound to ::sort at compile
> time.
>
> Question:
>
> is the function object template parameter to sort and other STL
> algorithms the only way this is done?  Is there a way I can pass a
> function object to a routine which then forwards the object to sort or
> must all function objects to sort be bound at compile time?  The examples
> I've seen in Stroustrup 3e and Musser/Saini have function objects
> whose values are known at compile time.

It takes some work, but I think you can do it.  By making the Compare
object a variant of James Coplien (Advanced C++) envelope-letter, you
can pass around a virtual implementation inside a compile-time shell.
The following was tested with Borland C++ 5.01.
------------------
#include <set.h>
#include <assert.h>

struct SetCompareImpl {
 virtual bool Compare(const int &, const int &) const=0;
 virtual SetCompareImpl *clone( )=0;
};

class SetCompare {
public:
 SetCompare( ):impl(0) {} //not really used, but needed for template
 SetCompare(SetCompareImpl &sci):impl(sci.clone( )) {}
 SetCompare(const SetCompare &rhs)
  :impl(rhs.impl->clone( )) {}
 ~SetCompare( ) { delete impl; }
 bool operator( )(const int &lhs, const int &rhs) const
  { assert(impl);return impl->Compare(lhs,rhs); }
private:
 SetCompareImpl *impl;
};

struct InOrder : public SetCompareImpl {
 virtual bool Compare(const int &, const int &) const;
 virtual InOrder *clone( );
};

struct OddFirst : public SetCompareImpl {
 virtual bool Compare(const int &, const int &) const;
 virtual OddFirst *clone( );
};

bool InOrder::Compare(const int &lhs, const int &rhs) const
{
 return lhs < rhs;
}

InOrder *InOrder::clone( )
{
 return new InOrder;
}

bool OddFirst::Compare(const int &lhs, const int &rhs) const
{
 if (lhs == rhs)
  return false;
 const bool leftOdd = lhs%2 == 1;
 const bool leftEven = !leftOdd;
 const bool rightOdd = rhs%2 == 1;
 const bool rightEven = !rightOdd;
 if (leftOdd && rightEven)
  return true;
 if (rightOdd && leftEven)
  return false;
 return lhs < rhs;
}

OddFirst *OddFirst::clone( )
{
 return new OddFirst;
}

namespace {
 int sampleList[] = {1,23,39,38,789,503,8,52,5,7,78,02,92,89,10};
 const int listSize = sizeof(sampleList)/sizeof(sampleList[0]);
};

void Show(std::set<int,SetCompare> &showSet)
{
 typedef std::set<int,SetCompare>::const_iterator Iter;
 const char tab = '\t';
 for (Iter iter=showSet.begin( );iter!=showSet.end( );iter++)
  cout << tab << *iter << endl;
}

int main( )
{
 SetCompare inorderCompare(static_cast<SetCompareImpl &>(InOrder( )));
 SetCompare oddFirstCompare(static_cast<SetCompareImpl &>(OddFirst( )));
 std::set<int,SetCompare> regular(inorderCompare);
 std::set<int,SetCompare>oddFirstSet(oddFirstCompare);
 for (int i=0;i<listSize;i++)
  {
  const int value = sampleList[i];
  regular.insert(value);
  oddFirstSet.insert(value);
  }
 cout << "regular set" << endl;
 Show(regular);
 cout << "odd first set" << endl;
 Show(oddFirstSet);
};
---------------------------
program produces the following output:

regular set
 1
 2
 5
 7
 8
 10
 23
 38
 39
 52
 78
 89
 92
 503
 789
odd first set
 1
 5
 7
 23
 39
 89
 503
 789
 2
 8
 10
 38
 52
 78
 92
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: ola@cs.duke.edu (Owen L. Astrachan)
Date: 1997/09/25
Raw View
I want to pass a function object to a method that will call
STL sort.  Here's a cut-down version of the code I want,
only relevant methods/classes shown.

class Compare
{
  public:
    virtual bool operator() (const DirEntry & lhs,
        const DirEntry & rhs) = 0;
};

class Scandir
{
  public:
    Scandir();
    void sort(Compare & comp);
  private:
    vector<DirEntry> myEntries;
};


void Scandir::sort(Compare & comp)
{
    ::sort(myEntries.begin(),myEntries.end(),comp);  // STL sort
}
-------
In the client program I'm deriving function objects
from Compare and passing them to the Scandir::sort function.

Problems:

However, the third "parameter" to sort is really a template
argument, and is thus bound at compile time rather than runtime,
I'm using the SGI STL implementation with a patched cygnus/g++
on a Sun/Solaris machine.

Also, I must supply a definition for Compare::operator() even though I
want it to be abstract (but the templated use of it precludes it being
"really abstract"), and this definition is bound to ::sort at compile
time.

Question:

is the function object template parameter to sort and other STL
algorithms the only way this is done?  Is there a way I can pass a
function object to a routine which then forwards the object to sort or
must all function objects to sort be bound at compile time?  The examples
I've seen in Stroustrup 3e and Musser/Saini have function objects
whose values are known at compile time.

-----------------------
Owen L. Astrachan
Associate Professor of the Practice of Computer Science
Director of Undergraduate Studies

Comp. Science: LSRC, D241             internet: ola@cs.duke.edu
Box 90129                             Phone (919) 660-6522
Duke University                       fax (919) 660-6519
Durham, NC 27708-0129                 http://www.cs.duke.edu/~ola
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]