Am I the only one struggling with this STL limitation?

Am I the only one struggling with this STL limitation?

Post by Carlos Moren » Tue, 20 Feb 2001 04:20:16



Well, maybe it's only a limitation inside my head...

Anyway, to the point:  say that I have objects that
don't support operator+ or operator+=  (say, because
the operations don't make sense for that particular
class).  The class, however, provides a method called
value().

Now, say that I have a vector (or any container) of
those objects, and I want to compute the sum of all
the values.

I feel that there has to be a nice and clean way for
me to use std::accumulate.  Other than creating my
own iterator class (which sounds horrible and overly
complicated, being the case that if I choose to use
std::accumulate is because I want to make my life
easier by typing less code and introducing less
chances of making mistakes), I'm out of ideas...

It sounds to me like I should be able to do something
like this:

total = accumulate (v.begin(), v.end(), something here);

where the something is some sort of adaptor that
translates the objects in the sequence into the
values being accumulated  (in this particular example,
the result of calling the method value() for every
object in the sequence).

But the only thing that can act as a third parameter
is a function object representing the operation (a
replacement for the +=)

Another example is when sorting.  Say that I have an
array of Persons -- clearly, sort is a meaningless
operation.  But sort by age, or sort by name, are
meaningful.  I kind of like the idea of being able
to tell std::sort to sort by the result of an
expression.  I know that in this case I can provide
my own version of operator< -- but, is it possible
to directly tell sort to sort on the result of an
operation on the object and not the object itself?
(sort may be a bad example, since the third parameter
does indeed allow to do what I'm trying to achieve;
it's just that I'm wondering if there is a way to
do it without bothering wiht the third parameter
for the comp operation...)

Thanks for any comments/ideas,

Carlos
--


      [ about comp.lang.c++.moderated. First time posters: do this! ]

 
 
 

Am I the only one struggling with this STL limitation?

Post by John Pott » Tue, 20 Feb 2001 15:13:53



Quote:> Anyway, to the point:  say that I have objects that
> don't support operator+ or operator+=  (say, because
> the operations don't make sense for that particular
> class).  The class, however, provides a method called
> value().

> Now, say that I have a vector (or any container) of
> those objects, and I want to compute the sum of all
> the values.

> It sounds to me like I should be able to do something
> like this:

> total = accumulate (v.begin(), v.end(), something here);

> where the something is some sort of adaptor that
> translates the objects in the sequence into the
> values being accumulated  (in this particular example,
> the result of calling the method value() for every
> object in the sequence).

> But the only thing that can act as a third parameter
> is a function object representing the operation (a
> replacement for the +=)

Nit: the third parameter is the initial value for the accumulator and
the fourth parameter is the one under discussion.


accum = op(accum, *it).  Let's assume a class C with the value function
returning an int and a vector<C> v.

int intPlusC (int lhs, C const& rhs) {
    return lhs + rhs.value();

Quote:}

    int total = accumulate(v.begin(), v.end(), 0, intPlusC)

It's not zero code but is easier than an iterator.  I think that
it was agreed that Iter::value_type need not be T for accumulate.

I guess that if it is needed often it could be templated as a class.
You might even use a pointer to member in place of value.

John


      [ about comp.lang.c++.moderated. First time posters: do this! ]

 
 
 

Am I the only one struggling with this STL limitation?

Post by Brian McNamar » Tue, 20 Feb 2001 15:14:49


Some interesting questions!


Quote:>Anyway, to the point:  say that I have objects that
>don't support operator+ or operator+=  (say, because
>the operations don't make sense for that particular
>class).  The class, however, provides a method called
>value().

>Now, say that I have a vector (or any container) of
>those objects, and I want to compute the sum of all
>the values.

>I feel that there has to be a nice and clean way for
>me to use std::accumulate.  Other than creating my

There is, see code below.

Quote:>Another example is when sorting.  Say that I have an
>array of Persons -- clearly, sort is a meaningless
>operation.  But sort by age, or sort by name, are
>meaningful.  I kind of like the idea of being able
>to tell std::sort to sort by the result of an
>expression.  I know that in this case I can provide
>my own version of operator< -- but, is it possible
>to directly tell sort to sort on the result of an
>operation on the object and not the object itself?
>(sort may be a bad example, since the third parameter
>does indeed allow to do what I'm trying to achieve;
>it's just that I'm wondering if there is a way to
>do it without bothering wiht the third parameter
>for the comp operation...)

Yes, but not with the standard functionals; you'll have to write one of
your own.  Again, see code below.  It's not clear to me that this one is
as useful in general.

Rather than try to do much explaining, I'll just post the code.  It's
short and I'm sure you can figure it out.  :)

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

using namespace std;

class Foo {
   int x;
   string s;
public:
   Foo( int xx, string ss ) : x(xx), s(ss) {}
   int value() const { return x; }
   string name() const { return s; }

Quote:};

// For first question
int accum_foo_values( int x, const Foo& f ) {
   return x + f.value();

Quote:}

// For second question
int foo_value( Foo f ) { return f.value(); }
string foo_name( Foo f ) { return f.name(); }

// h(x,y) = f( g(x), g(y) )
template <class F, class G>
struct hxy : public binary_function< typename G::argument_type,
                                     typename G::argument_type,
                                     typename F::result_type > {
   F f;
   G g;
public:
   hxy( const F& ff, const G& gg ) : f(ff), g(gg) {}
   result_type operator()( first_argument_type x,
                           second_argument_type y ) const {
      return f( g(x), g(y) );
   }

Quote:};

template <class F, class G>
hxy<F,G> f_gx_gy( const F& f, const G& g ) { return hxy<F,G>(f,g); }

int main() {
// For first question
   vector<Foo> v;
   v.push_back( Foo(1,"one") );
   v.push_back( Foo(2,"two") );
   v.push_back( Foo(3,"three") );
   cout << accumulate( v.begin(), v.end(), 0, accum_foo_values ) << endl;

// For second question
   sort( v.begin(), v.end(), f_gx_gy( less<int>(), ptr_fun(foo_value) ) );
   for( vector<Foo>::iterator i = v.begin(); i != v.end(); ++i )
      cout << i->value() << endl;

   sort( v.begin(), v.end(), f_gx_gy( less<string>(), ptr_fun(foo_name) ) );
   for( vector<Foo>::iterator i = v.begin(); i != v.end(); ++i )
      cout << i->name() << endl;

Quote:}

--

   ** Reduce - Reuse - Recycle **    :  (Where's my medication? ;) )


      [ about comp.lang.c++.moderated. First time posters: do this! ]

 
 
 

Am I the only one struggling with this STL limitation?

Post by Francis Glassboro » Tue, 20 Feb 2001 15:16:19




Quote:>Another example is when sorting.  Say that I have an
>array of Persons -- clearly, sort is a meaningless
>operation.  But sort by age, or sort by name, are
>meaningful.  I kind of like the idea of being able
>to tell std::sort to sort by the result of an
>expression.  I know that in this case I can provide
>my own version of operator< -- but, is it possible
>to directly tell sort to sort on the result of an
>operation on the object and not the object itself?
>(sort may be a bad example, since the third parameter
>does indeed allow to do what I'm trying to achieve;
>it's just that I'm wondering if there is a way to
>do it without bothering wiht the third parameter
>for the comp operation...)

Yes, write a telepathic implementation of C++ that can determine your
intent without being told:)

Seriously, how on Earth do you expect any computer algorithm to know
something as fundamental as how to compare two things unless you are
willing to tell it? All C++ does is to provide sane defaults that work
out of the box and meet frequent needs.

--
Francis Glassborow
See http://www.accu.org for details of The ACCU Spring Conference, 2001
(includes many regular participants to C & C++ newsgroups)


      [ about comp.lang.c++.moderated. First time posters: do this! ]

 
 
 

Am I the only one struggling with this STL limitation?

Post by Sai Shanka » Tue, 20 Feb 2001 15:21:11



> Well, maybe it's only a limitation inside my head...

> Anyway, to the point:  say that I have objects that
> don't support operator+ or operator+=  (say, because
> the operations don't make sense for that particular
> class).  The class, however, provides a method called
> value().

> Now, say that I have a vector (or any container) of
> those objects, and I want to compute the sum of all
> the values.

> I feel that there has to be a nice and clean way for
> me to use std::accumulate.  

And that's your mistake :-)

Here's what you can do with for_each (you need the shared_ptr from
Boost http://www.boost.org )

#include <functional>
#include "smart_ptr.hpp"

template <class T, class ReturnType>
struct Sum_t : public std::unary_function <T, ReturnType>
{
  Sum_t (ReturnType (T::*funcptr) (), ReturnType* sum): sum_(sum)
  {
    funcptr_ = funcptr;
  }

  ReturnType operator () (T const& t)
  {
    return *sum_ += (t.*funcptr_) ();
  }

  ReturnType value () const { return *sum_; }

  ReturnType (T::*funcptr_) ();

  boost::shared_ptr<ReturnType> sum_;

Quote:};

template <class T, class ReturnType>
Sum_t <T, ReturnType>
Sum (ReturnType (T::*funcptr) (), ReturnType* sum)
{
  return Sum_t <T, ReturnType> (funcptr, sum);

Quote:}

struct S
{
  S (int i): i_ (i) { }
  int f () { return i_; }
  int i_;

Quote:};

#include <iostream>
#include <vector>
#include <algorithm>

int main ()
{
  std::vector <S> vec;

  vec.push_back (S (1));
  vec.push_back (S (2));
  vec.push_back (S (3));
  vec.push_back (S (4));
  vec.push_back (S (5));
  vec.push_back (S (6));
  vec.push_back (S (7));
  vec.push_back (S (8));
  vec.push_back (S (9));
  vec.push_back (S (10));

  int i = 0;

  std::for_each (vec.begin (), vec.end (), Sum (S::f, &i));

  std::cout << i << "\n";

Quote:}

Hope this helps,

Regards
Sai Shankar


      [ about comp.lang.c++.moderated. First time posters: do this! ]

 
 
 

Am I the only one struggling with this STL limitation?

Post by Sai Shanka » Wed, 21 Feb 2001 00:40:05


[Refer to previous post]

Quote:

>   int i = 0;

    // This, of course, is wrong: Wisdom comes after posting :-)
    // Allocate this on the heap (make it a shared_ptr) and pass
    // it to for_each.

Quote:

>   std::for_each (vec.begin (), vec.end (), Sum (S::f, &i));


      [ about comp.lang.c++.moderated. First time posters: do this! ]
 
 
 

Am I the only one struggling with this STL limitation?

Post by Carlos Moren » Wed, 21 Feb 2001 04:46:19



> > But the only thing that can act as a third parameter
> > is a function object representing the operation (a
> > replacement for the +=)

> Nit: the third parameter is the initial value for the accumulator and
> the fourth parameter is the one under discussion.

Oops...  :-)


> accum = op(accum, *it).

That was actually a bad choice of words (honest!).  I should have
said a "replacement" for +  (but since the accumulate does something
with a behaviour equivalent to the +=, this one came to mind)

Quote:> int intPlusC (int lhs, C const& rhs) {
>     return lhs + rhs.value();
> }

>     int total = accumulate(v.begin(), v.end(), 0, intPlusC)

Ok, this one solves this particular problem...  I was talking
of a more general problem, and I was using this as an example.

My "general" question was if there is a way to apply some
"easy" (i.e., short and quick) modification to the STL
algorithms so that they act on the result of an operation
of each object of the sequence, instead of the object.

For instance, say that I want to find the youngest person
in a vector of Persons (being Person a class that provides
a method `int Person::age() const').  I feel somewhat tempted
to do something like this:

    min_element (p.begin(), p.end(), mem_fun_ref(&Person::age))

As opposed to:

    min_element (p.begin(), p.end(), my_compare_person_ages);

That is, not telling each algorithm the specific way on
comparing or adding or fill-in-the-blank on two objects, but
rather telling the algorithm to act not on the persons, but
on the specified operation for every person...

Is it possible?  My feeling is that it is not, but I'm affraid
that my conclusion could be due to my lack of knowledge on
certain features of the STL...  Is it the case?

Thanks!

Carlos
--


      [ about comp.lang.c++.moderated. First time posters: do this! ]

 
 
 

Am I the only one struggling with this STL limitation?

Post by Brian McNamar » Wed, 21 Feb 2001 06:40:06



Quote:>My "general" question was if there is a way to apply some
>"easy" (i.e., short and quick) modification to the STL
>algorithms so that they act on the result of an operation
>of each object of the sequence, instead of the object.

>For instance, say that I want to find the youngest person
>in a vector of Persons (being Person a class that provides
>a method `int Person::age() const').  I feel somewhat tempted
>to do something like this:

>    min_element (p.begin(), p.end(), mem_fun_ref(&Person::age))

>As opposed to:

>    min_element (p.begin(), p.end(), my_compare_person_ages);

>That is, not telling each algorithm the specific way on
>comparing or adding or fill-in-the-blank on two objects, but
>rather telling the algorithm to act not on the persons, but
>on the specified operation for every person...

>Is it possible?  My feeling is that it is not, but I'm affraid
>that my conclusion could be due to my lack of knowledge on
>certain features of the STL...  Is it the case?

I thought I'd answered this indirectly before, but in case it was
missed:

   min_element(p.begin(), p.end(),
               f_gx_gy( less<int>(), mem_fun_ref(&Person::age));

where f_gx_gy is the composer I posted earlier.

You can't change the fact that STL functions expect comparators (which
work on the value_type), but you can easily modify a comparator to act
on a function of its values (using f_gx_gy).

--

   ** Reduce - Reuse - Recycle **    :  (Where's my medication? ;) )


      [ about comp.lang.c++.moderated. First time posters: do this! ]

 
 
 

Am I the only one struggling with this STL limitation?

Post by Carlos Moren » Wed, 21 Feb 2001 10:15:15



> I thought I'd answered this indirectly before, but in case it was
> missed:

>    min_element(p.begin(), p.end(),
>                f_gx_gy( less<int>(), mem_fun_ref(&Person::age));

> where f_gx_gy is the composer I posted earlier.

> You can't change the fact that STL functions expect comparators (which
> work on the value_type), but you can easily modify a comparator to act
> on a function of its values (using f_gx_gy).

No, your post got to my news reader, and then to my screen!  Thanks!

You are sort of answering my question, in that it looks like what
I was trying to do can not be done  (well, it's not so much that I
was trying to do it -- it's rather I was wondering if it could be
done).

Yes, I did know that providing my own custom function object would
lead me to the required result -- it's just that it looks to me
like more complicated than the problem I'm trying to solve (which
is coding a for loop to accumulate, or to find the highest, or
whatever other of the STL algorithms that are relatively simple).

I mean, having to create a class, and then creating one with a
built-in library function object, and a member function adaptor
looks kind of three times more complex than just doing:

container::const_iterator min_elem = persons.begin();
for (container::const_iterator i = persons.begin(); i != persons.end();
++i)
{
    if (*i < *min_elem) min_element = i;

Quote:}

It's just that I had the feeling that it would (should?) be possible
to easily and quickly tell *directly* an algorithm to act on an
operation on the objects, rather than on the objects themselves.
When I say *directly*, I mean not through the use of comparison
or other operations, where you indirectly achieve the same effect.

Well, at least I don't feel that my lack of knowledge was too deep!  :-)

Thanks all for your comments!

Carlos
--


      [ about comp.lang.c++.moderated. First time posters: do this! ]

 
 
 

Am I the only one struggling with this STL limitation?

Post by Eugene Karpach » Thu, 22 Feb 2001 01:11:07


19 Feb 2001 14:46:19 -0500 Carlos Moreno ?D:

Quote:>My "general" question was if there is a way to apply some
>"easy" (i.e., short and quick) modification to the STL
>algorithms so that they act on the result of an operation
>of each object of the sequence, instead of the object.

It seems that you need sort of "iterator adaptor". You could look to
Boost (http://www.boost.org) for examples or ready-to-use code.

--
jk


      [ about comp.lang.c++.moderated. First time posters: do this! ]

 
 
 

Am I the only one struggling with this STL limitation?

Post by Brian McNamar » Thu, 22 Feb 2001 01:12:20




>>    min_element(p.begin(), p.end(),
>>                f_gx_gy( less<int>(), mem_fun_ref(&Person::age));

>I mean, having to create a class, and then creating one with a
>built-in library function object, and a member function adaptor
>looks kind of three times more complex than just doing:

>container::const_iterator min_elem = persons.begin();
>for (container::const_iterator i = persons.begin(); i != persons.end();
>++i)
>{
>    if (*i < *min_elem) min_element = i;
>}

Agreed.  Would that we could say

   min_element(p.begin(), p.end(), lambda(x,y) { x.age() < y.age() } );

as in functional languages.  The problem (inconvenience, really), IMO,
is not so much with the STL algorithms/interface/design as it is with
C++ itself.

Quote:>It's just that I had the feeling that it would (should?) be possible
>to easily and quickly tell *directly* an algorithm to act on an
>operation on the objects, rather than on the objects themselves.
>When I say *directly*, I mean not through the use of comparison
>or other operations, where you indirectly achieve the same effect.

You may be interested in Dietmar's paper from the template workshop, if
you haven't seen it:

   http://www.oonumerics.org/tmpw00/kuehl.html

He presents an alternative design for STL containers which separates the
notion of 'holders' from 'values held'.  He uses an example of
containers of pointers to polymorphic object (that we want to view as
just a polymorphic container of objects), but my hunch is that the same
strategy might apply here (considering the Person to be the holder
for the Age).  I confess I've not thought about it enough.  In any case,
have a look, as I think you may enjoy it or find it enlightening.

--

   ** Reduce - Reuse - Recycle **    :  (Where's my medication? ;) )


      [ about comp.lang.c++.moderated. First time posters: do this! ]

 
 
 

Am I the only one struggling with this STL limitation?

Post by maxi » Thu, 22 Feb 2001 11:27:12


the following is a bit of a mess and needs some refactoring work, but you
can use it like this:

struct Annotation{... int page_; ...int Length(){...}};
 std::list<Annotation>::iterator toInsert =
    std::lower_bound( m_annot.begin(), m_annot.end(),
         a,
         MakeEvaluator(&Annotation::page_)
        );

vector<Annotation> aVec;
or
std::sort(aVec.begin(), aVec.end(), MakeEvaluator(&Annotation::Length));

#ifndef MEMBEREVALUATOR_H_
#define MEMBEREVALUATOR_H_

template<class objT, class valT>
struct EvaluateData
{
 typedef valT (objT::*memPtrT);
 typedef objT objType;
 typedef valT valType;
 valT evaluate(const objT& obj, memPtrT ptr){return (obj.*ptr);}
 valT evaluate(const objT& obj, memPtrT ptr) const {return (obj.*ptr);}

};

template<class objT, class valT>
struct Evaluate0
{
 typedef valT (objT::*memPtrT)();
 typedef objT objType;
 typedef valT valType;
 valT evaluate(const objT& obj, memPtrT ptr){return (obj.*ptr)();}
 valT evaluate(const objT& obj, memPtrT ptr) const {return (obj.*ptr)();}

};

template<class objT, class valT, class p1T>
struct Evaluate1
{
 typedef valT (objT::*memPtrT)(p1T);
 typedef objT objType;
 typedef valT valType;
 p1T p1_;
 Evaluate1(p1T p1):p1_(p1){}
 valT evaluate(const objT& obj, memPtrT ptr){return (obj.*ptr)(p1_);}
 valT evaluate(const objT& obj, memPtrT ptr) const {return (obj.*ptr)(p1_);}

};

template<class objT, class valT, class p1T, class p2T>
struct Evaluate2
{
 typedef valT (objT::*memPtrT)(p1T, p2T);
 typedef objT objType;
 typedef valT valType;
 p1T p1_;
 p2T p2_;
 Evaluate2(p1T p1, p2T p2):p1_(p1), p2_(p2){}
 valT evaluate(const objT& obj, memPtrT ptr){return (obj.*ptr)(p1_, p2_);}
 valT evaluate(const objT& obj, memPtrT ptr) const {return (obj.*ptr)(p1_,
p2_);}

};

template<class objT, class valT,class p1T, class p2T, class p3T>
struct Evaluate3
{
 typedef valT (objT::*memPtrT)(p1T, p2T, p3T);
 typedef objT objType;
 typedef valT valType;
 p1T p1_;
 p2T p2_;
 p3T p3_;
 Evaluate3(p1T p1, p2T p2, p3T p3):p1_(p1), p2_(p2), p3_(p3){}
 valT evaluate(const objT& obj, memPtrT ptr){return (obj.*ptr)(p1_, p2_,
p3_);}
 valT evaluate(const objT& obj, memPtrT ptr) const {return (obj.*ptr)(p1_,
p2_, p3_);}

};

template<class objT, class valT, class p1T, class p2T, class p3T, class p4T>
struct Evaluate4
{
 typedef valT (objT::*memPtrT)(p1T, p2T, p3T, p4T);
 typedef objT objType;
 typedef valT valType;
 p1T p1_;
 p2T p2_;
 p3T p3_;
 p4T p4_;
 Evaluate4(p1T p1, p2T p2, p3T p3, p4T p4):p1_(p1), p2_(p2), p3_(p3),
p4_(p4){}
 valT evaluate(const objT& obj, memPtrT ptr){return (obj.*ptr)(p1_, p2_,
p3_, p4_);}
 valT evaluate(const objT& obj, memPtrT ptr) const {return (obj.*ptr)(p1_,
p2_, p3_, p4_);}

};

template<class objT, class valT, class p1T, class p2T, class p3T, class p4T,
class p5T>
struct Evaluate5
{
 typedef valT (objT::*memPtrT)(p1T, p2T, p3T, p4T, p5T);
 typedef objT objType;
 typedef valT valType;
 p1T p1_;
 p2T p2_;
 p3T p3_;
 p4T p4_;
 p5T p5_;
 Evaluate5(p1T p1, p2T p2, p3T p3, p4T p4, p5T p5)
  :p1_(p1), p2_(p2), p3_(p3), p4_(p4), p5_(p5)
 {}
 valT evaluate(const objT& obj, memPtrT ptr){return (obj.*ptr)(p1_, p2_,
p3_, p4_, p5_);}
 valT evaluate(const objT& obj, memPtrT ptr) const {return (obj.*ptr)(p1_,
p2_, p3_, p4_, p5_);}

};

template<class objT, class valT,
   class p1T, class p2T, class p3T, class p4T, class p5T, class p6T>
struct Evaluate6
{
 typedef valT (objT::*memPtrT)(p1T, p2T, p3T, p4T, p5T, p6T);
 typedef objT objType;
 typedef valT valType;
 p1T p1_;
 p2T p2_;
 p3T p3_;
 p4T p4_;
 p5T p5_;
 p6T p6_;
 Evaluate6(p1T p1, p2T p2, p3T p3, p4T p4, p5T p5, p6T p6)
  :p1_(p1), p2_(p2), p3_(p3), p4_(p4), p5_(p5), p6_(p6)
 {}
 valT evaluate(const objT& obj, memPtrT ptr){return (obj.*ptr)(p1_, p2_,
p3_, p4_, p5_, p6_);}
 valT evaluate(const objT& obj, memPtrT ptr) const {return (obj.*ptr)(p1_,
p2_, p3_, p4_, p5_, p6_);}

};

template<class objT, class valT,
   class p1T, class p2T, class p3T, class p4T, class p5T, class p6T, class
p7T>
struct Evaluate7
{
 typedef valT (objT::*memPtrT)(p1T, p2T, p3T, p4T, p5T, p6T, p7T);
 typedef objT objType;
 typedef valT valType;
 typedef valT (objT::*memPtrT)(p1T, p2T, p3T, p4T, p5T, p6T, p7T);
 p1T p1_;
 p2T p2_;
 p3T p3_;
 p4T p4_;
 p5T p5_;
 p6T p6_;
 p7T p7_;
 Evaluate7(p1T p1, p2T p2, p3T p3, p4T p4, p5T p5, p6T p6, p7T p7)
  :p1_(p1), p2_(p2), p3_(p3), p4_(p4), p5_(p5), p6_(p6), p7_(p7)
 {}
 valT evaluate(const objT& obj, memPtrT ptr){return (obj.*ptr)(p1_, p2_,
p3_, p4_, p5_, p6_, p7_);}
 valT evaluate(const objT& obj, memPtrT ptr) const {return (obj.*ptr)(p1_,
p2_, p3_, p4_, p5_, p6_, p7_);}

};

template<class objT, class valT,
   class p1T, class p2T, class p3T, class p4T, class p5T, class p6T,
   class p7T, class p8T>
struct Evaluate8
{
 typedef valT (objT::*memPtrT)(p1T, p2T, p3T, p4T, p5T, p6T, p7T, p8T);
 typedef objT objType;
 typedef valT valType;
 p1T p1_;
 p2T p2_;
 p3T p3_;
 p4T p4_;
 p5T p5_;
 p6T p6_;
 p7T p7_;
 p8T p8_;
 Evaluate8(p1T p1, p2T p2, p3T p3, p4T p4, p5T p5, p6T p6, p7T p7, p8T p8)
  :p1_(p1), p2_(p2), p3_(p3), p4_(p4), p5_(p5), p6_(p6), p7_(p7), p8_(p8)
 {}
 valT evaluate(const objT& obj, memPtrT ptr){return (obj.*ptr)(p1_, p2_,
p3_, p4_, p5_, p6_, p7_, p8_);}
  valT evaluate(const objT& obj, memPtrT ptr) const {return (obj.*ptr)(p1_,
p2_, p3_, p4_, p5_, p6_, p7_, p8_);}

};

template<class objT, class valT,
   class p1T, class p2T, class p3T, class p4T, class p5T, class p6T,
   class p7T, class p8T, class p9T>
struct Evaluate9
{
 typedef valT (objT::*memPtrT)(p1T, p2T, p3T, p4T, p5T, p6T, p7T, p8T, p9T);
 typedef objT objType;
 typedef valT valType;
 p1T p1_;
 p2T p2_;
 p3T p3_;
 p4T p4_;
 p5T p5_;
 p6T p6_;
 p7T p7_;
 p8T p8_;
 p9T p9_;
 Evaluate9(p1T p1, p2T p2, p3T p3, p4T p4, p5T p5, p6T p6, p7T p7, p8T p8,
p9T p9)
  :p1_(p1), p2_(p2), p3_(p3), p4_(p4), p5_(p5), p6_(p6), p7_(p7), p8_(p8),
p9_(p9)
 {}
 valT evaluate(const objT& obj, memPtrT ptr){return (obj.*ptr)(p1_, p2_,
p3_, p4_, p5_, p6_, p7_, p8_, p9_);}
 valT evaluate(const objT& obj, memPtrT ptr) const {return (obj.*ptr)(p1_,
p2_, p3_, p4_, p5_, p6_, p7_, p8_, p9_);}

};

template<class objT, class valT,
   class p1T, class p2T, class p3T, class p4T, class p5T, class p6T,
   class p7T, class p8T, class p9T, class p10T>
struct Evaluate10
{
 typedef valT (objT::*memPtrT)(p1T, p2T, p3T, p4T, p5T, p6T, p7T, p8T, p9T,
p10T);
 typedef objT objType;
 typedef valT valType;
 p1T p1_;
 p2T p2_;
 p3T p3_;
 p4T p4_;
 p5T p5_;
 p6T p6_;
 p7T p7_;
 p8T p8_;
 p9T p9_;
 p10T p10_;
 Evaluate10(p1T p1, p2T p2, p3T p3, p4T p4, p5T p5, p6T p6, p7T p7, p8T p8,
p9T p9, p10T p10)
  :p1_(p1), p2_(p2), p3_(p3), p4_(p4), p5_(p5), p6_(p6), p7_(p7), p8_(p8),
p9_(p9), p10_(p10)
 {}
 valT evaluate(const objT& obj, memPtrT ptr) const {return (obj.*ptr)(p1_,
p2_, p3_, p4_, p5_, p6_, p7_, p8_, p9_, p10_);}
 valT evaluate(const objT& obj, memPtrT ptr){return (obj.*ptr)(p1_, p2_,
p3_, p4_, p5_, p6_, p7_, p8_, p9_, p10_);}

};

template<class evalT>
struct ComparerAndEvaluator
{
 evalT   eval_;
 evalT::memPtrT ptr_;
 typedef evalT::objType argument_type;
 bool operator()(const evalT::objType& ls, const evalT::objType& rs){ return
eval_.evaluate(ls, ptr_) < eval_.evaluate(rs, ptr_);}
 evalT::valType operator()(const evalT::objType& obj){return
eval_.evaluate(obj, ptr_);}
 evalT::valType operator()(const evalT::objType& obj) const {return
eval_.evaluate(obj, ptr_);}
 ComparerAndEvaluator(evalT eval, evalT::memPtrT ptr):eval_(eval),
ptr_(ptr){}

};

template<class T, class valT>
ComparerAndEvaluator<EvaluateData<T, valT> >
MakeEvaluator(valT (T::*pmem))
{
 return ComparerAndEvaluator<EvaluateData<T, valT> >(EvaluateData<T,
valT>(), pmem);

}

template<class T, class valT>
ComparerAndEvaluator<Evaluate0<T, valT> >
MakeEvaluator(valT (T::*pmem)())
{
 return ComparerAndEvaluator<Evaluate0<T, valT> >(Evaluate0<T, valT>(),
pmem);

}

template<class T, class valT, class p1T>
ComparerAndEvaluator<Evaluate1<T, valT, p1T> >
MakeEvaluator(valT (T::*pmem)(p1T), p1T p1)
{
 typedef Evaluate1<T, valT, p1T> Evaluator;
 return ComparerAndEvaluator<Evaluator>(Evaluator(p1), pmem);

}

template<class T, class valT, class p1T, class p2T>
ComparerAndEvaluator<Evaluate2<T, valT, p1T, p2T> >
MakeEvaluator(valT (T::*pmem)(p1T, p2T), p1T p1, p2T p2)
{
 typedef Evaluate2<T, valT, p1T, p2T> Evaluator;
 return ComparerAndEvaluator<Evaluator>(Evaluator(p1, p2), pmem);

}

template<class T, class valT, class p1T, class p2T, class p3T>
ComparerAndEvaluator<Evaluate3<T, valT, p1T, p2T, p3T> >
MakeEvaluator(valT (T::*pmem)(p1T, p2T, p3T), p1T p1, p2T p2, p3T p3)
{
 typedef Evaluate3<T, valT, p1T, p2T, p3T> Evaluator;
 return ComparerAndEvaluator<Evaluator>(Evaluator(p1, p2, p3), pmem);

}

template<class T, class valT, class p1T, class p2T, class p3T, class p4T>
ComparerAndEvaluator<Evaluate4<T, valT, p1T, p2T, p3T, p4T> >
MakeEvaluator(valT (T::*pmem)(p1T, p2T, p3T, p4T), p1T p1, p2T p2, p3T p3,
p4T p4)
{
 typedef Evaluate4<T, valT, p1T, p2T, p3T, p4T> Evaluator;
 return ComparerAndEvaluator<Evaluator>(Evaluator(p1, p2, p3, p4), pmem);

}

template<class T, class valT, class p1T, class p2T, class p3T, class p4T,
   class p5T>
ComparerAndEvaluator<Evaluate5<T, valT, p1T, p2T, p3T, p4T, p5T> >
MakeEvaluator(valT (T::*pmem)(p1T, p2T, p3T, p4T, p5T), p1T p1, p2T p2, p3T
p3, p4T p4, p5T p5)
{
 typedef Evaluate5<T, valT, p1T, p2T, p3T, p4T, p5T>  Evaluator;
 return ComparerAndEvaluator<Evaluator>(Evaluator(p1, p2, p3, p4, p5),
pmem);

}

template<class T, class valT, class p1T, class p2T, class p3T, class p4T,
   class p5T, class p6T>
ComparerAndEvaluator<Evaluate6<T, valT, p1T, p2T, p3T, p4T, p5T, p6T> >
MakeEvaluator(valT (T::*pmem)(p1T, p2T, p3T, p4T, p5T, p6T), p1T p1, p2T p2,
p3T p3,
              p4T p4, p5T p5, p6T p6)
{
 typedef Evaluate6<T, valT, p1T, p2T, p3T, p4T, p5T, p6T>  Evaluator;
 return ComparerAndEvaluator<Evaluator>(Evaluator(p1, p2, p3, p4, p5, p6),
pmem);

}

template<class T, class valT, class p1T, class p2T, class p3T, class p4T,
   class p5T, class p6T, class p7T>
...

read more »

 
 
 

Am I the only one struggling with this STL limitation?

Post by John Pott » Thu, 22 Feb 2001 13:39:36



Quote:> My "general" question was if there is a way to apply some
> "easy" (i.e., short and quick) modification to the STL
> algorithms so that they act on the result of an operation
> of each object of the sequence, instead of the object.

> For instance, say that I want to find the youngest person
> in a vector of Persons (being Person a class that provides
> a method `int Person::age() const').  I feel somewhat tempted
> to do something like this:

>     min_element (p.begin(), p.end(), mem_fun_ref(&Person::age))

Your initial thought on a custom iterator may be the way to go.  If
someone else does the work, it may be just what you need.  This is
from a quick look; so, it may not be correct.

#include <boost/iterator_adaptors.hpp>

SomeContainer::iterator it = min_element(
   make_transform_iterator(p.begin(), mem_fun_ref(&Person::age)),
   make_transform_iterator(p.end(), mem_fun_ref(&Person::age))).base();

John


      [ about comp.lang.c++.moderated. First time posters: do this! ]

 
 
 

Am I the only one struggling with this STL limitation?

Post by To » Fri, 23 Feb 2001 02:46:04






>>>    min_element(p.begin(), p.end(),
>>>                f_gx_gy( less<int>(), mem_fun_ref(&Person::age));

>>I mean, having to create a class, and then creating one with a
>>built-in library function object, and a member function adaptor
>>looks kind of three times more complex than just doing:

>>container::const_iterator min_elem = persons.begin();
>>for (container::const_iterator i = persons.begin(); i != persons.end();
>>++i)
>>{
>>    if (*i < *min_elem) min_element = i;
>>}

>Agreed.  Would that we could say

>   min_element(p.begin(), p.end(), lambda(x,y) { x.age() < y.age() } );

>as in functional languages.  The problem (inconvenience, really), IMO,
>is not so much with the STL algorithms/interface/design as it is with
>C++ itself.

I think with the Lambda library
(http://lambda.cs.utu.fi/lambda_functions.html)
it would look like this:

min_element(p.begin(), p.end(), free1->*(&Person::age) <
free2->*(&Person::age));

which is ok but hardly ideal.

Still, until compilers get better, functional programming libraries
for C++ will have limited appeal.

Tom


      [ about comp.lang.c++.moderated. First time posters: do this! ]

 
 
 

Am I the only one struggling with this STL limitation?

Post by Siemel Nara » Sat, 24 Feb 2001 00:33:06



> Anyway, to the point:  say that I have objects that
> don't support operator+ or operator+=  (say, because
> the operations don't make sense for that particular
> class).  The class, however, provides a method called
> value().

> Now, say that I have a vector (or any container) of
> those objects, and I want to compute the sum of all
> the values.
> total = accumulate (v.begin(), v.end(), something here);

What happenned to std::compose?  STL defines these overloaded functions,
but the standard does not.  Did the standards committee remove compose?

What you want is

struct MyAdd : public binary_function<int,const Thing&,int> {
   int operator()(int lhs, const Thing& rhs) const { return
lhs+rhs.value(); }

Quote:};

Can't think of the lambda classes required to generate this.

--
+++++++++++
Siemel Naran


      [ about comp.lang.c++.moderated. First time posters: do this! ]

 
 
 

1. Help I am struggling with ExtDeviceMode function

Help,
I am trying to use the ExtDeviceMode function to change a
printerparameter
without having to call the printer driver's dialogbox.
Calling the printerdriver dll gives no problem and a valid handle.
Calling the DeviceMode (this is the older function) works fine
but calling ExtDeviceMode never works. (The program crashes - Exception
in
module ...)
I have followed the MS API description carefully and I have tried a
number
of ways to give the parameters to the function.
Has anybody successfully used ExtDeviceMode and do you have an example?
Thanks a lot

------
DANIEL ROGGE
Siemens Nixdorf Information Systems, Belgium
Phone +32-02-536 4716  Fax +32-02-536 4730

------
The opinions expressed in this message are mine and do not necessary
reflect
the opinion of Siemens Nixdorf.

2. draft mode

3. More struggles with STL

4. Have to reboot every week or logons start to fail..

5. DDB Win98 limitation 16MB for one or all?

6. HYPERACCESS/5 FOR OS/2 BE

7. Am I missing something about STL predicates?

8. Shortcuts not looking automatically for target in this install, why?

9. Am I the only one that finds this download system frustrating....?

10. Am trying to create my 1st dialog and am failing miserably...

11. Classes, I am not sure what i am doing wrong!

12. One verticle splitter with one horizontal splitter on one side