Thread: set of pointer to methods!

  1. #1
    Registered User
    Join Date
    Mar 2007
    Posts
    25

    set of pointer to methods!

    Hello,

    I'm trying to have a STL set of pointer-to-member-functions in my class. I already know how to declare and define pointers-to-functions and use them with an ordinary array, but using the STL containers has proven problematic.

    It kind of works with vectors if I choose to use .push_back(), but .insert() gives me errors. That said, I need to use set. So can anyone tell me how to fix this sample code?

    Code:
    #include <iostream>
    #include <set>
    
    using namespace std;
    
    class test{
    
    public:  
      test(){ p.insert( &test::g ); }
      int f(){ cout << " f() " << endl; }
      int g(){ cout << " g() " << endl; }
      int h(){ cout << " h() " << endl; }
    
      set< int(test::*)() > p;
    
    };
    
    
    int main(int argc, char *argv[]){
    
      test a_test;
    
      ((a_test).*(a_test.begin()))();
    
    }
    Thanks

  2. #2
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    5,108
    Code:
    ((a_test).*(*a_test.p.begin()))();
    Not that it is going to work.

    Soma

  3. #3
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    The error I get is that class test has no member named begin, which I believe. Do you want the beginning of p? Then you should probably use p.begin. If I do
    Code:
    a_test.*(a_test.p.begin())();
    then I get errors claiming that set (or more specifically, operator<) doesn't know how to compare objects of type int (test::* const)().
    What sorts of errors are you trying to fix?

  4. #4
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    5,108
    Code:
    a_test.*(a_test.p.begin())();
    O_o

    The STL containers' 'begin' methods returns an iterator.

    Also, the surrounding parentheses isn't optional.

    Soma

  5. #5
    Registered User
    Join Date
    Mar 2007
    Posts
    25
    well, that .begin() call was a typo, so sorry about that. If I was to use a vector then the call would look something like ((a_test).*(a_test.p[0]))();

    But that's not my concer. I want to know how to use set and insert(). You can comment out ((a_test).*(a_test.begin()))();. Right now I want to know how to get p.insert( &test::g ); working.

    This is the kind of errors that I'm getting:
    Code:
    -*- mode: compilation; default-directory: "~/Programming/CPP/" -*-
    Compilation started at Sun Dec  7 21:35:52
    
    g++ -o t03 t03.cpp
    /usr/lib/gcc/x86_64-pc-linux-gnu/4.1.2/include/g++-v4/bits/stl_function.h: In member function 'bool std::less<_Tp>::operator()(const _Tp&, const _Tp&) const [with _Tp = int (test::*)()]':
    /usr/lib/gcc/x86_64-pc-linux-gnu/4.1.2/include/g++-v4/bits/stl_tree.h:921:   instantiated from 'std::pair<typename std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::iterator, bool> std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::insert_unique(const _Val&) [with _Key = int (test::*)(), _Val = int (test::*)(), _KeyOfValue = std::_Identity<int (test::*)()>, _Compare = std::less<int (test::*)()>, _Alloc = std::allocator<int (test::*)()>]'
    /usr/lib/gcc/x86_64-pc-linux-gnu/4.1.2/include/g++-v4/bits/stl_set.h:321:   instantiated from 'std::pair<typename std::_Rb_tree<_Key, _Key, std::_Identity<_Key>, _Compare, typename _Alloc::rebind<_Key>::other>::const_iterator, bool> std::set<_Key, _Compare, _Alloc>::insert(const _Key&) [with _Key = int (test::*)(), _Compare = std::less<int (test::*)()>, _Alloc = std::allocator<int (test::*)()>]'
    t03.cpp:9:   instantiated from here
    /usr/lib/gcc/x86_64-pc-linux-gnu/4.1.2/include/g++-v4/bits/stl_function.h:227: error: invalid operands of types 'int (test::* const)()' and 'int (test::* const)()' to binary 'operator<'
    
    Compilation exited abnormally with code 1 at Sun Dec  7 21:35:52

  6. #6
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    Yes, you're right, I'm a * short. I can make
    Code:
    (a_test.*(*(a_test.p.begin())))()
    work with a list, but not with a set.

  7. #7
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    5,108
    Bolding things for no good reason may upset people. You probably shouldn't do it again if you expect help.

    Anyway, the problem I see is with your logic. A 'set' is by definition a unique sorted associative container. A function, the function itself, doesn't really have a value that can be sorted.

    If you think you must do this... you must use idiocy:

    Code:
    struct idiocy
    {
      bool operator()(int(test::*p1)(), int(test::*p2)()) const
      {
        return false;
      }
    };
    Soma

  8. #8
    3735928559
    Join Date
    Mar 2008
    Location
    RTP
    Posts
    838
    your life would probably be easier if you used function objects


    Code:
    //---------------------------------------------------------------------------
    #include <set>
    #include <iostream>
    #pragma hdrstop
    
    //---------------------------------------------------------------------------
    
    #pragma argsused
    
    class c{
            public:
            int iifunc(int i){return i*i;};
    };
    class fptr
    {
            public:
            virtual void __fastcall exec()=0;
    };
    template<typename classtype,typename returntype,typename argtype>class tfptr : public fptr
    {
            typedef returntype (classtype::*funcPtr)(argtype);
    
            public:
                    argtype &input;
                    returntype *output;
                    funcPtr func;
                    classtype &cinst;
                    tfptr(classtype &classinstance,funcPtr function,argtype&arg) :
                            cinst(classinstance),
                            func(function),
                            input(arg),
                            output(NULL)
                    {
                    }
                    virtual void __fastcall exec()
                    {
                            if(output)
                            {
                                    *output = (cinst.*func)(input);
                            }
                            else
                            {
                                    (cinst.*func)(input);
                            }
                    }
    };
    //---------------------------------------------------------------------------
    int main(int argc, char* argv[])
    {
            c c1;
            int output;
            int input = 2;
            std::set<fptr*>funcs;
            tfptr<c,int,int>f(c1,&c::iifunc,input);
            f.output = &output;
            funcs.insert(&f);
            (*funcs.begin())->exec();
    
            cout<<output;
            int i;
            cin>> i;
            return 0;
    }
    Last edited by m37h0d; 12-08-2008 at 12:47 AM.

  9. #9
    Registered User
    Join Date
    Mar 2007
    Posts
    25
    Thanks m37h0d. I didn't know about functionoids (or function objects), but I've been working with them for the past few weeks. I like them.

    As for my original problem, I now use a set of functionoids instead of regular class methods. My code runs twice as fast now then before when I was using class methods, or pointer to functions. I don't understand why it's running faster though; the functionoids are still a function call and I'm not using templates.

  10. #10
    Registered User C_ntua's Avatar
    Join Date
    Jun 2008
    Posts
    1,853
    Well, without the whole code, or knowing exactly what you are doing it is hard to tell. You can post the code (don't post the actual classes if you don't want to, just main).

    The function object offers simplicity and better organization, which often leads to a better code, the latest usually being faster

  11. #11
    Registered User
    Join Date
    Mar 2007
    Posts
    25
    okay, I'll post my code and I hope I get to learn something new again.
    I went digging up one of my older git test branch commits where I was trying to get the functionoids to work. The project is a Fractal Flame renderer. The Transformer class is responsible for setting up each transformer, and all the transformer objects created share a vector<float> where they dump the calculated points in. The Variation class is the functionoid which replaces all the Transformer methods that I had before that calculated the variations for each transformer.

    I'm posting mainly the .h files just to keep it short.


    Here is the Variation class. I'm not so sure what to do with the destructors; I've left them all empty. I'm still thinking of all these as functions.
    Code:
    #ifndef VARIATIONS_H
    #define VARIATIONS_H
    
    #include <vector>
    using namespace std;
    
    class Variation{
     public:
      virtual vector<float> Compute(float *) = 0;
      virtual ~Variation() = 0;
    };
    
    class Linear : public Variation{
     public:
      virtual ~Linear();
      virtual vector<float> Compute(float *);
      float linearWeight;
      vector<float> destinXY;
    };
    
    class Sinusoidal : public Variation{
     public:
      virtual ~Sinusoidal();
      virtual vector<float> Compute(float *);
      float sinusoidalWeight;
      vector<float> destinXY;
    };
    
    class Spherical : public Variation{
     public:
      virtual ~Spherical();
      virtual vector<float> Compute(float *);
      float sphericalWeight;
      vector<float> destinXY;
    };
    #endif
    Here is the Transformer class. linear, sinusoidal, and spherical were at first just ordinary methods before I learned about functionoids.
    Code:
    #ifndef TRANSFORMER_H
    #define TRANSFORMER_H
    
    #include <vector>
    #include <set>
    
    #include "variations.h"
    
    using namespace std;
    
    class Transformer{
    
     public:
      Transformer();
      Transformer(float, float, float, float, float, float);
      Transformer(const Transformer &);
      ~Transformer();
    
      void setLinearWeight(float);
      void setSinusoidalWeight(float);
      void setSphericalWeight(float);
      void setTransformerOXY(float, float, float, float, float, float);
      int RunTransformation();
      void ClearPoints();
      vector<float>::iterator container();
    
     private:
    //The functionoids to calculate variations
      Linear linear;
      Sinusoidal sinusoidal;
      Spherical spherical;
    
      //Weight of each varation                 
      float linearWeight;
      float sinusoidalWeight;
      float sphericalWeight;
      
      //List of varation functions to call
      set<Variation *> todoList;
      
      //Single point storage                  
      float sourceXY[2];
      float targetXY[2];
      vector<float> destinXY;
    
      float transformerOXY[3][2];
    
      //Final points storage
      static vector<float> points; //evens = x, odds = y
      vector<float>::iterator itX;
      vector<float>::iterator itY;
    };
    #endif
    Here is the Transformer::RunTransformation() that performs twice as fast now with functionoids. The for loops is where the functionoids are called. Before I would call the methods.

    Code:
    int Transformer::RunTransformation(){
    
      itY = --points.end();
      itX = itY - 1;
      sourceXY[0] = *itX;
      sourceXY[1] = *itY;
    
      targetXY[0] = sourceXY[0];
      targetXY[1] = sourceXY[1];
    
      //Translation
      targetXY[0] += transformerOXY[0][0];
      targetXY[1] += transformerOXY[0][1];
    
      //Scale
      targetXY[0] *= transformerOXY[1][0];
      targetXY[1] *= transformerOXY[2][1];
    
      //Shear
      targetXY[0] += 2 * (transformerOXY[2][0] * (targetXY[1] - transformerOXY[0][1]));
      targetXY[1] += 2 * (transformerOXY[1][1] * (targetXY[0] - transformerOXY[0][0]));
    
      set<Variation *>::iterator it;
      it = todoList.begin();
    
      for(int i = 0; i < todoList.size(); i++){
        destinXY = (*it)->Compute(targetXY);
      }
      points.push_back(destinXY[0]);
      points.push_back(destinXY[1]);
    
      return 0;
    }

  12. #12
    Registered User C_ntua's Avatar
    Join Date
    Jun 2008
    Posts
    1,853
    Code:
      for(int i = 0; i < todoList.size(); i++){
        destinXY = (*it)->Compute(targetXY);
      }
    Wouldn't this rewrite destinXY ???

  13. #13
    Registered User
    Join Date
    Mar 2007
    Posts
    25
    yes it would, but like I said, it's from a test branch. I was testing the individual linear function to see if it was doing what it was supposed to do and I changed "+= "to "=" .

  14. #14
    3735928559
    Join Date
    Mar 2008
    Location
    RTP
    Posts
    838
    beats me why it's faster; i just know they will save your behind on large-scale highly-abstracted projects.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. optimising program
    By SONU in forum C Programming
    Replies: 1
    Last Post: 05-18-2008, 10:28 AM
  2. Pong is completed!!!
    By Shamino in forum Game Programming
    Replies: 11
    Last Post: 05-26-2005, 10:50 AM
  3. Compiler "Warnings"
    By Jeremy G in forum A Brief History of Cprogramming.com
    Replies: 24
    Last Post: 04-24-2005, 01:09 PM
  4. problem with open gl engine.
    By gell10 in forum Game Programming
    Replies: 1
    Last Post: 08-21-2003, 04:10 AM
  5. Set Classes
    By Nicknameguy in forum C++ Programming
    Replies: 3
    Last Post: 10-21-2002, 07:40 PM