Advertisement

How to use mem_fun with for_each correctly

Started by July 12, 2001 10:51 AM
16 comments, last by Kylotan 23 years, 7 months ago
quote:

Magmai : You are right, it can be a pain in the ass to create a functor, but with a functor performance is much higher. Because the compiler can inline everything.


Inline it more than a macro does? And in my particular case the functions are virtual anyway

Are there other mem_fun like functions that let you pass parameters? Or would that require custom function adaptors for each method? Or is there someway to use mem_fun_xxx with unary_function / binary_function to generate the adaptor?

Can you recommend any books on the STL Stoffel?

Magmai Kai Holmlor
- The disgruntled & disillusioned
- The trade-off between price and quality does not exist in Japan. Rather, the idea that high quality brings on cost reduction is widely accepted.-- Tajima & Matsubara
quote:
Original post by Stoffel
Original post by Gorg
mem_fun is suppose to compile to the correct version, mem_fun1, but this only works if the compiler supports Partial template specialization.


This is incorrect. mem_fun's constructor tells all:

It is correct, it is in the C++ standard. mem_fun should resolve to the correct number of param.

Actually I found new stuff, and you can make VC++ use mem_fun for 1 argument attribute also

here is the excerpt from borlands header file :

    template <class S, class T>   class mem_fun_t  : public unary_function<T*,S>  {    S (T::*pmf)();  public:    _EXPLICIT mem_fun_t(S (T::*p)()) : pmf(p)    { ; }    S operator()(T* p) const    { return (p->*pmf)(); }  };  template <class S, class T, class A>   class mem_fun1_t : public binary_function<T*,A,S>  {    S (T::*pmf)(A);  public:    _EXPLICIT mem_fun1_t(S (T::*p)(A)) : pmf(p)    { ; }    S operator()(T* p, A a) const    { return (p->*pmf)(a); }  };  template <class S, class T>   inline mem_fun_t<S,T> mem_fun(S (T::*f)())  {    return mem_fun_t<S,T>(f);  }  template <class S, class T, class A>   inline mem_fun1_t<S,T,A> mem_fun(S (T::*f)(A))  {    return mem_fun1_t<S,T,A>(f);  }    


See what they do. They create a function mem_fun which returns a mem_fun1

You can do the same thing with VC++.


A great book on the STL is : http://www.amazon.com/exec/obidos/ASIN/0201379260/ref=lm_lb_6/104-1773197-6899106

There is also Effective STL which is fresh off the press :
http://www.amazon.com/exec/obidos/ASIN/0201749629/qid=995145295/sr=1-1/ref=sc_b_1/104-1773197-6899106



To extend it, you need to write a trinary_function template then write a mem_fun2_t struct and then your mem_fun function with 3 arguments.

You will need new types of binders : mainly bind1sdAnd2nd, bind1stand3rd, bind2ndAnd3dr.






Edited by - Gorg on July 14, 2001 5:38:35 PM
Advertisement
Wow, all these informative replies, and I only fully understand about 25% of them

JD: I agree - sometimes it's easier to use your own for() loop rather than struggling to work out the exact syntax for what you want to do. But, once you work it out, you can save yourself some time forever, which is why I posted this

I'm using MSVC6.0 SP3 (acronyms R us) with the standard dinkumware STL. Can't use STLport because it requires all that library compilation up-front.

Stoffel: I think I see what you mean now. I was expecting mem_fun to return a function object that would be given a single parameter, but in fact it returns a function object that is parameterised by the object it gets called upon. Which makes sense. The fact that the member function required another parameter just made it more complicated, and required the binder object. I think. Anyway, you said "mem_fun calls a member function of Creature*", whereas it looks to me like, in my example, mem_fun was expecting an App* from for_each, and it was actually getting Creature*, hence the error. Is this right?

Void: I'm sure the definition you gave is right, it just made no sense All those meaningless variable names for hypothetical parameters does my head in. I can only handle worked examples

MKH: "AFAICT, You have to create a new functor for each & every method you want to use with for_each." What's the problem with this? After all, as was shown in the assembly listing below, when such an object contains no members (99% of the time) it gets optimised away to nothing. And when it does have members, that's some sort of state that you would have had to preserve anyway. Maybe there's something I'm missing though, not really being an STL expert.

Thanks everybody for the detailed discussion.

Edited by - Kylotan on July 15, 2001 11:40:16 AM
quote:
Original post by Kylotan

Stoffel: I think I see what you mean now. I was expecting mem_fun to return a function object that would be given a single parameter, but in fact it returns a function object that is parameterised by the object it gets called upon. Which makes sense. The fact that the member function required another parameter just made it more complicated, and required the binder object. I think. Anyway, you said "mem_fun calls a member function of Creature*", whereas it looks to me like, in my example, mem_fun was expecting an App* from for_each, and it was actually getting Creature*, hence the error. Is this right?



You can use mem_fun with 2 parameters in 2 manners :

1. Call a member function on each object in the container.

2. Call a function on object passing the all elements in the container to it.


You wanted to 2.

Here is the code : You just need to remember one thing, when using member function, the this* is the first param.

#1
    class Test{ public:    void Print( int i ) const  //need to change void and const to make it build in VC++   {       std::cout << "i" << std::endl;   }};std::vector<Test*> testContainer;//fill the container up//this will print a list of 3for_each( testContainer.begin(),          testContainer.end(),          bind2nd( mem_fun(&Test::print), 3 );//use bind2nd because the function will be called like this :Test::print( testContainer[i], 3 );  



#2
        //uses Test class abovestd::vector<int> intContainter;//fill the vectorTest t;//this will print the list of integer in the vectorfor_each( intContainer.begin(),          intContainer.end(),          bind1st( mem_fun(&Test::print), & t ));//use bind1st, because this pointer is first, so resolve to something likeTest::print( &t, intContainer[i] );    


A lot of people find it ugly. You get use to it. The thing above is very simple and clear.

Don't forget, Most of those things are classes. So can create it outside the class and write comments and pass the created object to for_each.

  std::vector<int> intContainer;//fill the containerTest t;//sorry the var namesstd::bind1st funcBinder( mem_fun(&Test::print), & t );for_each( intContainer.begin(),          intContainer.end(),          funcBinder );  


Edited by - Gorg on July 15, 2001 12:27:35 PM
quote:
Original post by Kylotan
All those meaningless variable names for hypothetical parameters does my head in. I can only handle worked examples



What I do is to look at the last line and guess 8)

It defines its member function operator() as returning (p->*pm)().


It calls ( function pointer)(), so it must be so.

One of the annoying things I find about STL is that the function adapters doesn''t seems complete. They are addition useful adapters like (compose_f_gx/compose1, etc) outlined in boost that should be standardised.
Kylotan,

There are two ways to use stlport. One, as a half-stl meaning containers and such are their but you''re using vc++ streams. Second, you use their sgi improved streams i.e. the whole enchilada.

In first case, all you have to do to use stlport is to uncomment ONE line in one header file and point your compiler to their stl directory. Make sure their stl directory is listed before vc++ one. That I got working no problem. There is an error in uncommenting a line in wrong header file. You uncomment the line in user settings header file not global settings header file. Frankly there is no line like that mentioned in global settings header that is mentioned in their installation docs.

Second case, requires to recompile the whole stl and this is where I have a problem. The nmake doesn''t build the files because it can''t find some files. Three I think. It would be a lot easier for them to include vc++ project files and not make files. Then again I don''t really want to use stlport because I like the somewhat informative dinkum stl docs in msdn. There are no stl docs for stlport that I''m aware of and although I have sgi stl docs god knows what has changed between stlport and sgi stl. Maybe nothing but I''m not so sure. I also have c++ standard but it isn''t as nice to look over nor informative as the msdn one. So I stick with msdn until I get the hang of it and then will move to stlport perhaps. The stlport is faster than dinkums so at least that''s an incentive to go with stlport.
Advertisement
quote:

MKH: "AFAICT, You have to create a new functor for each & every method you want to use with for_each." What''s the problem with this? After all, as was shown in the assembly listing below, when such an object contains no members (99% of the time) it gets optimised away to nothing. And when it does have members, that''s some sort of state that you would have had to preserve anyway. Maybe there''s something I''m missing though, not really being an STL expert.


I didn''t realize that mem_fun/mem_fun1/bind1st/etc... could create these adaptors for you. I thought you had to code them yourself, I figured there was something that I was missing

Magmai Kai Holmlor
- Not For Rent
- The trade-off between price and quality does not exist in Japan. Rather, the idea that high quality brings on cost reduction is widely accepted.-- Tajima & Matsubara
quote:
Original post by Magmai Kai Holmlor
I didn''t realize that mem_fun/mem_fun1/bind1st/etc... could create these adaptors for you. I thought you had to code them yourself, I figured there was something that I was missing

The problem with the STL, is that it can do pretty much everything. You just have to know how!
  #include "algorithm"for_each(humanity.begin(), humanity.end(), end_world_poverty);  

Nice to have a thread where several of us learn something new. I picked up the Josuttis STL book yesterday as it''s apparent that the true power of the standard library can only be appreciated once you fully understand it and have a good reference.

This topic is closed to new replies.

Advertisement