Thread: for_each: callback function

  1. #1
    Registered User Russell's Avatar
    Join Date
    May 2004
    Posts
    71

    for_each: callback function

    How do I get the for_each algorithm to use the objects function (line 17)?
    Code:
          1 #include <iostream>
          2 #include <list>
          3 
          4 class MyClass
          5 {
          6 public:
          7   MyClass();
          8   ~MyClass();
          9   std::list<int> l;
         10   void Print(int i);
         11 };
         12 
         13 MyClass::MyClass()
         14 {
         15   for (int a=0;a<11;++a)
         16     l.push_back(a);
         17   std::for_each(l.begin(),l.end(),Print);
         18 }
         19 MyClass::~MyClass()
         20 {
         21 }
         22 void MyClass::Print(int i)
         23 {
         24   std::cout<<i<<std::endl;
         25 }
         26 
         27 
         28 int main(int argc,char* argv[])
         29 {
         30   MyClass mc;
         31   return 0;
         32 }

  2. #2
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,981
    You can't use class member function as a for_each functor.
    You can use a static member function, a regular function, or a functor object.
    Code:
    #include<algorithm>
    #include<iostream>
    #include<list>
    using namespace std;
    
    struct PrintFunctor : public unary_function<int, void>
    {
        void operator()(int n) const
        { 
            cout << n << endl;
        }//operator()
    };//PrintFunctor
    
    void PrintFunction(int n)
    {
        cout << n << endl;
    }//PrintFunction
    
    int main()
    {
        list<int> l;
        for (int n = 0; n < 10; n++)
            l.push_back(n);
    
        for_each(l.begin(), l.end(), PrintFunctor());
        for_each(l.begin(), l.end(), PrintFunction);
    
        return 0;
    }//main
    You don't have to inherit from unary_function<>, but it's a good habit.

    gg

  3. #3
    Registered User Russell's Avatar
    Join Date
    May 2004
    Posts
    71
    Well, that's a shame. I'll just use a for loop. Thanks, Codeplug.

  4. #4
    Registered User hk_mp5kpdw's Avatar
    Join Date
    Jan 2002
    Location
    Northern Virginia/Washington DC Metropolitan Area
    Posts
    3,817
    Quote Originally Posted by Codeplug
    You can't use class member function as a for_each functor.
    Should be able to do it using mem_fun_ref. I've done it before using different compilers MSVC++ 6.0 and MSVC .NET. Depending on the compiler I've used you need to do different things to get it to work. Under MSVC++ 6.0, the function being called needed to return a value and be non-const, i.e.:

    Code:
    #include <functional>
    #include <algorithm>
    #include <iostream>
    #include <list>
    
    class MyClass
    {
    public:
        MyClass();
        ~MyClass();
        std::list<int> l;
        int Print(int i);
    };
    
    MyClass::MyClass()
    {
        for (int a=0;a<11;++a)
            l.push_back(a);
        std::for_each(l.begin(),l.end(),std::mem_fun_ref(MyClass::Print));
    }
    
    MyClass::~MyClass()
    {
    }
    
    int MyClass::Print(int i)
    {
        std::cout<<i<<std::endl;
        return 0;
    }
    
    int main(int argc,char* argv[])
    {
        MyClass mc;
        return 0;
    }
    However, MSVC .NET wanted the called function to be a type void, const function:

    Code:
    #include <functional>
    #include <algorithm>
    #include <iostream>
    #include <list>
    
    class MyClass
    {
    public:
        MyClass();
        ~MyClass();
        std::list<int> l;
        void Print(int i) const;
    };
    
    MyClass::MyClass()
    {
        for (int a=0;a<11;++a)
            l.push_back(a);
        std::for_each(l.begin(),l.end(),std::mem_fun_ref(MyClass::Print));
    }
    
    MyClass::~MyClass()
    {
    }
    
    void MyClass::Print(int i) const
    {
        std::cout<<i<<std::endl;
    }
    
    int main(int argc,char* argv[])
    {
        MyClass mc;
        return 0;
    }
    [edit]Added #include <algorithm> for the for_each function.[/edit]

    [edit2]I just realized that this won't work because you are expecting an arugment to be passed to the Print function. You can pass an argument to the function also by using bind2nd as in:

    Code:
        std::for_each(l.begin(),l.end(),std::bind2nd(std::mem_fun_ref(MyClass::Print),1));
    But as you see, you need a specific value to give as the second parameter, you can't really use what you were trying to print out the members of the list. You could however replace the for_each call with a call to copy and just to this:

    Code:
    std::copy(l.begin(),l.end(),std::ostream_iterator<int>(cout,"\n"))
    [/edit2]
    Last edited by hk_mp5kpdw; 06-03-2004 at 08:03 AM.
    "Owners of dogs will have noticed that, if you provide them with food and water and shelter and affection, they will think you are god. Whereas owners of cats are compelled to realize that, if you provide them with food and water and shelter and affection, they draw the conclusion that they are gods."
    -Christopher Hitchens

  5. #5
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,981
    Well, no version of MSVC, or any compiler for that matter, will compile that mem_fun_ref<> code.

    std::mem_fun_ref<> is usefull if you want to call member functions of objects within the container.

    >> std::for_each(l.begin(),l.end(),std::mem_fun_ref(M yClass::Print));
    This says, "call the MyClass member function Print(), for each of the MyClass instances within l".
    The compiler will have a hard time doing that since "l" contains int's and not MyClass's.

    I like what you're thinking, but I don't know of anything in std:: that will do it.

    We can certainly do it ourselves though.....chew on this:
    Code:
    #include <functional>
    #include <algorithm>
    #include <iostream>
    #include <list>
    using namespace std;
    
    // This class represents an adaptor for calling a class member function on 
    // a particular class instance as if it were simply a unary functor with void 
    // return type.
    template<class mem_fun_t,  // member function pointer type
             class instance_t, // class type containing member function
             class param_t>    // parameter type of member function
    struct call_mem_fun_t : public unary_function<param_t, void> 
    {
        // constructor
        //  pmf - pointer to member function
        //  inst - instance to use when calling member function
        explicit call_mem_fun_t(mem_fun_t pmf, instance_t *inst)
            : m_pmf(pmf), m_inst(inst) {}
    
        // functor
        void operator()(param_t &val) const
        {
            (m_inst->*m_pmf)(val); 
        }// operator()
    
    private:
        mem_fun_t m_pmf;    // pointer to member function
        instance_t *m_inst; // pointer to instance in order to call member function
    };//call_mem_fun_t
    
    
    // This is a utility template function for constructing and returning a 
    // call_mem_fun_t<> object. The actual "utility" is that the compiler will 
    // deduce template arguments for us.
    // Note that the compiler has a hard time deducing param_t only based on 
    // the mem_fun_t type. So it is the first template parameter and should be
    // specified.
    template<class param_t,    // param_t goes first since compiler can't figure it out
             class mem_fun_t,  // member function pointer type
             class instance_t> // class type containing member function
    inline
    call_mem_fun_t<mem_fun_t, instance_t, param_t> // return type
    call_mem_fun(mem_fun_t pmf, instance_t *inst)
    {
        return call_mem_fun_t<mem_fun_t, instance_t, param_t>(pmf, inst);
    }//call_mem_fun
    
    
    // Test class for our adaptors
    class MyClass
    {
        list<int> m_ilist;
    
    public:
        MyClass()
        {
            for (int n = 0; n < 10; n++)
                m_ilist.push_back(n);
    
            // use call_mem_fun_t directly
            for_each(m_ilist.begin(), m_ilist.end(),
                     call_mem_fun_t<void (MyClass::*)(int), // member function pointer type
                                    MyClass,                // class type containing member function
                                    int>                    // parameter type of member function
                                   (&MyClass::Print, this));// call Print() using 'this'
            
            cout << "--------" << endl;
    
            // now use the "utility" function
            for_each(m_ilist.begin(), m_ilist.end(), 
                     call_mem_fun<int>(&MyClass::Print, this)); // I can read this!!
        }//constructor
    
        void Print(int i)
        {
            cout << i << endl;
        }//Print
    };//MyClass
    
    
    int main()
    {
        MyClass mc;
    
        return 0;
    }//main
    gg
    Last edited by Codeplug; 06-03-2004 at 12:23 PM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Screwy Linker Error - VC2005
    By Tonto in forum C++ Programming
    Replies: 5
    Last Post: 06-19-2007, 02:39 PM
  2. Game Pointer Trouble?
    By Drahcir in forum C Programming
    Replies: 8
    Last Post: 02-04-2006, 02:53 AM
  3. callback function v. regular function
    By 7stud in forum C++ Programming
    Replies: 8
    Last Post: 03-24-2005, 11:34 AM
  4. c++ linking problem for x11
    By kron in forum Linux Programming
    Replies: 1
    Last Post: 11-19-2004, 10:18 AM
  5. Is it possible to have callback function as a class member?
    By Aidman in forum Windows Programming
    Replies: 11
    Last Post: 08-01-2003, 11:45 AM