Thread: vector of function pointers

  1. #1
    Registered User
    Join Date
    Feb 2003
    Posts
    596

    vector of function pointers

    I'm trying to achieve the following:
    (1) main() should not be modified by my user
    (2) user provides a file (or files) containing functions all of the same type and same number and type of arguments, but the details of what the functions do are left to the user.
    (3) main somehow gets a vector of pointers to those functions and the determination of which functions are called occurs at runtime.

    I came up with the following dumb example of how I can accomplish this (the user would provide both funcs.h and func.cpp), but I'm wondering if there's a better way. I'm not thrilled with the idea of making the user include the array (funcArr) of function pointers, but I couldn't think of any other way to load main's funcs vector.

    Code:
    // fn_pointer.cpp
    
    #include <iostream>
    #include <vector>
    #include "funcs.h"
    using namespace std;
    
    
    int main () {
      vector<int (*)(int,int)> funcs(&(*funcArr), &(*funcArr)+NUM_FUNCS);
      int x,y,op,sum;
      cout << "1. add\n2. multiply\n\tChoose 1 or 2\n";
      cin >> op;
      cout << "enter 2 operands:\n";
      cin >> x >> y;
      sum = funcs[op-1](x,y);
      cout << "the result is " << sum << "\n";
    }
    Code:
    // funcs.h
    
    #ifndef funcs_h_
    #define funcs_h_
    
    const int NUM_FUNCS = 2;
    int add(int,int);
    int mult(int,int);
    
    int (*funcArr[])(int, int) = {add, mult};
    
    #endif
    Code:
    // funcs.cpp
    
    int add(int x, int y) {return x + y;}
    int mult(int x, int y) {return x * y;}

  2. #2
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    What is the purpose of doing this?

    One way of doing this is to make use of some kind of "registry" (presumably a singleton). Each user defined function would have to register themselves, then the main function would merely consult the registry to determine what functions to call.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  3. #3
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,660
    Perhaps a user-supplied init() function, which takes your funcs vector as a ref parameter would be better.

    But then how do you know that "1" is "add" ?

    If you used a map, like
    map< string, int (*)(int,int) > funcs;

    Then
    funcs["add"] = add;
    could be done by the user.

    Then in your main(), you could print out the key names as part of your menu.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  4. #4
    Registered User
    Join Date
    Feb 2003
    Posts
    596
    Sorry, the menu is just something I threw in there so I could see that the pointers were doing what I wanted. I've never done a vector of function pointers before. Main doesn't have to know what the functions do. The arguments will all be const so the only requirement is that they return "allowed" values. I'll have code in main to ensure that.

    It's a driver program for a research project - game theory actually. Main runs the games, keeps track of scores, prints results, etc. funcs.cc provides the rules determining the players' moves. I'm trying to make it as convenient as possible to modify the set of available rules.

    Maybe I'm missing something, but I don't see why a user-supplied init() function would be better. The user would still need some sort of list of the functions or pointers to them, for the init() to iterate through in order to load the vector, right? Simply providing an array seems to be easier.

    Laserlight, I'm curious about your suggestion, but I really have no idea what that would look like (or what a singleton is). Can you point me to something to read that explains it?

  5. #5
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by R.Stiltskin
    Laserlight, I'm curious about your suggestion, but I really have no idea what that would look like (or what a singleton is). Can you point me to something to read that explains it?
    You should search the Web for singleton pattern. The pattern itself is less important than the idea that functions register themselves.

    I suggested the registry idea because it is used in some unit test frameworks. Unit test frameworks face a similiar problem as you: ideally, the driver code is written once and users add tests in one or more source files. When new tests are added there should be no need to modify the driver code. If there was, then failure to update that file would mean that the new test is not run, which is a Bad Thing. On the other hand, failure to update the registry would mean the same thing, so the frameworks may end up requiring the use of macros or template magic to ensure that tests are always registered.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  6. #6
    Registered User
    Join Date
    Feb 2003
    Posts
    596
    That may be more complicated than I need for this purpose, but it sounds interesting anyway so I will look into it. Thanks.

  7. #7
    Registered User
    Join Date
    Nov 2005
    Posts
    673
    A singleton is a very basic concept really.
    You can use lazy instantiation, or controlled. Lazy is fine if it does not matter who/what creates the singleton first, but is not ok if the creation time matters(rare case IMO).

    This is a basic class using lazy instantiation.(not tested so may have syntax error)
    Code:
    class MySingleton
    {
    private:
      MySingleton() {};
      ~MySingleton() {};
    
      static MySingleton* m_Singleton;
    
    public:
      static MySingleton* Get()
      {
         if ( !m_Singleton )
            m_Singleton = new MySingleton();
         return m_Singleton;
       }
    
       static void Release()
       { 
           if ( m_Singleton )
          {
             delete m_Singleton;
             m_Singleton = 0;
           }
        }
    };
    
    //To use it
    MySingleton* Test = MySingleton::Get();
    
    //Don't forget to release it when your done
    MySingleton::Release();
    The other way is pretty simple to figure out.

  8. #8
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    5,108
    The pattern itself is less important than the idea that functions register themselves.
    Can you elaborate on this issue?

    I'm... extremely curious as to how you would handle this.

    Soma

  9. #9
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by phantomotap
    Can you elaborate on this issue?
    Take a look at TUT and UnitTest++ since these are the unit test frameworks I had in mind when I suggested the registry idea. The last I rumaged through TUT's code some time back it had a registry as a singleton and used template magic to have test functions automatically register themselves (unfortunately, it also appeared to abuse exception handling to control the flow of control). UnitTest++ uses macros instead, but despite being a regular UnitTest++ user I must confess that I have not taken a deep enough look into how it works to explain how it does automagic test detection.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  10. #10
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    5,108

    Post

    Take a look at TUT [...] does automagic test detection.
    I see.

    Well, from what I can guess from the provided examples:

    'TUT' uses a fully specialized template as a discontinuous namespace for defining template functions which all share the same name and performs simple recursion to register the valid ones. (That's actually pretty clever, but it isn't a full testing framework.)

    'UnitTest++' looks like a truly evil affair by using macros as a means of mugging the names of target functions for creating classes and super classes which register the given test or suite in the constructor of the generated class. (Which is very ugly besides, but it does seem to provide more testing primitives than I usually see.)

    The thing is, neither of these actually present a solution where the function "registers" itself. I was expecting something more like:

    Code:
    bool testing
    (
       suite & f
    )
    {
       registry<my_test_suite>::register_function<&testing>();
       return(0 == 0); // Whatever!
    }
    Which in my opinion would provide semantics and context.

    Unfortunately, my library is the only code I've ever seen doing it.

    I'm always on the lookout for better methods you see.

    Thanks anyway.

    Soma

  11. #11
    Registered User
    Join Date
    Feb 2003
    Posts
    596
    I'm still playing with this, primarily out of curiousity. I think that my main function's vector of function pointers serves as a "registry" -- I don't see why anything more elaborate is needed. The question is just how it gets loaded.

    Implementing Salem's suggestion is straightforward enough:
    Code:
    // fn_pointer2.cpp
    
    #include <iostream>
    #include <vector>
    #include "funcs2.h"
    #include <cassert>
    using namespace std;
    
    
    int main () {
      vector<int (*)(int,int)> funcs;
      functions::regis(funcs);
      assert(!funcs.empty());
      int x,y,op,sum;
      cout << "1. add\n2. multiply\n\tChoose 1 or 2\n";
      cin >> op;
      cout << "enter 2 operands:\n";
      cin >> x >> y;
      sum = funcs[op-1](x,y);
      cout << "the result is " << sum << "\n";
    }
    Code:
    // funcs2.h
    
    #ifndef funcs2_h_
    #define funcs2_h_
    
    #include <vector>
    struct functions {
    
    static int add(int,int);
    static int mult(int,int);
    
    static void regis( std::vector<int (*)(int,int)>& );
    };
    
    #endif
    Code:
    // funcs2.cpp
    #include "funcs2.h"
    
    // user-provided registration function:
    // user can implement this either by adding a line for each function
    // or by iterating through an array containing a pointer to each function
    void functions::regis(std::vector<int (*)(int,int)> &registry) {
      registry.push_back(&add);
      registry.push_back(&mult);
    }
    
    int functions::add(int x, int y) {return x + y;}
    
    int functions::mult(int x, int y) {return x * y;}
    Then I thought I would see how this would be done in a class or struct. So I wrapped the functions in a struct (called "functions") & gave it a constructor that takes a vector of function pointers as an argument. Since now these are member functions, I had to change the type of the vector to <int (functions::*)(int,int)>. But now the compiler is complaining about the way the main function uses the pointers to call the functions & I can't figure out what it wants me to do.

    Here's the error:
    Code:
     g++ fn_pointer3.cpp funcs3.cpp
    fn_pointer3.cpp: In function `int main()':
    fn_pointer3.cpp:20: error: must use .* or ->* to call pointer-to-member
       function in `(&funcs)->std::vector<_Tp, _Alloc>::operator[] [with _Tp = int
       (functions::*)(int, int), _Alloc = std::allocator<int (functions::*)(int,
       int)>]((op - 1)) (...)'
    and here's the code:
    Code:
    // fn_pointer3.cpp
    
    #include <iostream>
    #include <vector>
    #include "funcs3.h"
    #include <cassert>
    using namespace std;
    
    
    int main () {
    //  vector<int (*)(int,int)> funcs;
      vector<int (functions::*)(int,int)> funcs;
      functions f(funcs);
      assert(!funcs.empty());
      int x,y,op,sum;
      cout << "1. add\n2. multiply\n\tChoose 1 or 2\n";
      cin >> op;
      cout << "enter 2 operands:\n";
      cin >> x >> y;
      sum = funcs[op-1](x,y);
      cout << "the result is " << sum << "\n";
    }
    Code:
    // funcs3.h
    
    #ifndef funcs3_h_
    #define funcs3_h_
    
    #include <vector>
    struct functions {
      functions( std::vector<int (functions::*)(int,int)> );
    
      int add(int,int);
      int mult(int,int);
    
    };
    
    #endif
    Code:
    // funcs3.cpp
    #include "funcs3.h"
    
    int functions::add(int x, int y) {return x + y;}
    
    int functions::mult(int x, int y) {return x * y;}
    
    functions::functions(std::vector<int (functions::*)(int,int)> registry) {
      registry.push_back(&functions::add);
      registry.push_back(&functions::mult);
    }

  12. #12

  13. #13
    3735928559
    Join Date
    Mar 2008
    Location
    RTP
    Posts
    838
    it also sounds like you might want to look into explicitly importing DLLs if you want to do this in a file-based context at runtime.

  14. #14
    Registered User
    Join Date
    Feb 2003
    Posts
    596
    Quote Originally Posted by m37h0d View Post
    it also sounds like you might want to look into explicitly importing DLLs if you want to do this in a file-based context at runtime.
    Yes, I need to learn a great deal about DLLs (including creating them) but that's another whole subject, for another day ...

  15. #15
    Registered User
    Join Date
    Feb 2003
    Posts
    596
    Sorry, but this only adds another layer to my confusion. If I read this correctly you have created a new type tfptr which includes among its members an instance of a class c, a pointer to a member function of c, and a member function exec() (of tfptr) which calls c's member function. The thing that you are putting into the container is a pointer to the tfptr object, so it makes sense that when you retrieve it from the container you use -> to call its exec() function.

    That's clearly different from my vector which contains pointers to member functions of my "functions" object. Are you saying that what I'm trying to do is illegal? Or am I just not seeing an answer that is staring me in the face?

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Class function pointers
    By VirtualAce in forum C++ Programming
    Replies: 40
    Last Post: 02-17-2005, 12:55 AM
  2. pointers
    By InvariantLoop in forum C Programming
    Replies: 13
    Last Post: 02-04-2005, 09:32 AM
  3. Request for comments
    By Prelude in forum A Brief History of Cprogramming.com
    Replies: 15
    Last Post: 01-02-2004, 10:33 AM
  4. Contest Results - May 27, 2002
    By ygfperson in forum A Brief History of Cprogramming.com
    Replies: 18
    Last Post: 06-18-2002, 01:27 PM
  5. function pointers and member functions
    By thor in forum C++ Programming
    Replies: 5
    Last Post: 03-19-2002, 04:22 PM