-1

How do I get the below code example, that compiles and works just fine to work inside a class?


Below code works just fine

#include <iostream>
using namespace std;

typedef int (*IntFunctionWithOneParameter) (int a);

int function(int a){ return a; }
int functionTimesTwo(int a){ return a*2; }
int functionDivideByTwo(int a){ return a/2; }

void main()
{
    IntFunctionWithOneParameter functions[] = 
    {
        function, 
        functionTimesTwo, 
        functionDivideByTwo
    };

    for(int i = 0; i < 3; ++i)
    {
        cout << functions[i](8) << endl;
    }
}

So the above code works fine, but I want to move it inside a class in a separate file, similar to the below NON-WORKING IDEA, where I get "incomplete type is not allowed" error at "functions[] =";

class myClass {
private:

  typedef int (*IntFunctionWithOneParameter) (int a);

  int function(int a){ return a; }
  int functionTimesTwo(int a){ return a*2; }
  int functionDivideByTwo(int a){ return a/2; }

  IntFunctionWithOneParameter functions[] = 
    {
        function, 
        functionTimesTwo, 
        functionDivideByTwo
    };
};

So my question is how can I get it to work inside my class, where it is the ONLY place the functions are needed, meaning I do need to access the functions in main() or other places!


EDIT

Here is why I need an "array of functions". To save time spent on "if's" or more exactly "switches" as I am making a software (vst) synthesizer, and the less time spent in the processing, the more notes (polyphonic) the user can play at any given time. And multiply the 44100 times per second the function is run, with 8 tone generators, which each can have up to 16 unison voices, so actually the function needed, may be called up to 5,644,800 times per second, per note played! The exact function needed inside this main loop is known BEFORE entering loop, and ONLY changes when the user adjust a knob, so I do want to avoid ifs and switches. Now had it only been one function that occasionally changes, i could just duplicate main loop with variations for each function possible, HOWEVER the main audio processing loop, has several areas, each with a variety of ever growing functions possible, each which ONLY changes when user changes various knobs. So although I could, I am not going to make 5 * 20 * 23 (and growing) different versions of a main loop, to avoid if's and switches.

  • 1
    Member functions are not simple function pointers. Are you sure you need to use member functions? How do you know on what object you have to call them? – Yksisarvinen Mar 15 '20 at 12:35
  • 1
    The error message is because you can't create arrays with implicit sizes like your inline in a class or structure definition. You *must* specify the size, or use `std::vector` instead. – Some programmer dude Mar 15 '20 at 12:36
  • 2
    I also recommend that you open your book on the chapter of function pointers, and learn the difference between a pointer to a non-member function and a pointer to a member function. They are different (as mentioned already). You could also use *type-erasure* for the function pointer and use e.g. [`std::function`](https://en.cppreference.com/w/cpp/utility/functional/function) instead. – Some programmer dude Mar 15 '20 at 12:38
  • I may not be using the right terminology, but I edited the post showing an example I found online, which compiles and works just fine! – DKDiveDude Mar 15 '20 at 12:43
  • The issue you are getting is due to a function being a non-static member function. It alone doesn't mean anything, you need some sort of object to refer to it. Ex: `myClass owo; owo.function1();` – Marcin Poloczek Mar 15 '20 at 12:43
  • @DKDiveDude The issue is that your example is using free (global) functions. Free functions and class member functions are wildly different. We are trying to learn *why* you want to using pointers to member function to be able to provide an answer or alternatives. – Yksisarvinen Mar 15 '20 at 12:58
  • @Yksisarvinen I edited original post to explain why I need something equivalent to an array of functions. – DKDiveDude Mar 15 '20 at 14:10

3 Answers3

1

There's a bunch of things wrong with the code that you posted:

  • No semicolon after class definition.
  • Class instead of class
  • No fixed size set for the functions member, which is not allowed. You need to explicitly set the size of the array.
  • Member function pointers are not the same as "regular" function pointers. Member function pointers have an implicit this as first argument, since they need an object to be invoked on. So myFunction is not of type myArrayOfFunctions. If you make myFunction and myFunction2 static, then they can be stored as regular function pointers. Is this an option?
  • The name myArrayOfFunctions is very confusing, since it's not an array at all.

All but the last of these will cause your code not to compile.

AVH
  • 11,349
  • 4
  • 34
  • 43
  • Ok I just quickly typed in some example code, I'll try and edit to correct typos. – DKDiveDude Mar 15 '20 at 12:45
  • Did anyone commenting, actually look at the lower half of my post which shows code, similar to mine, except is it not in a class, that compiles and works just fine? – DKDiveDude Mar 15 '20 at 12:52
  • @DKDiveDude That's is completely different code: no free functions vs class member functions, non-member array, ... – AVH Mar 15 '20 at 12:54
  • I fail to see how the code is different, except my names are different, and it is inside a class, but let me edit my original post and use the code that worked. – DKDiveDude Mar 15 '20 at 13:01
0

This example may be what you've needed.

Note: I've changed typedef statement to using and changed function's signatures to take in plain int for testing convinience sake.

class myClass {
public:
    using myArrayOfFunctions = float(myClass::*)(int a, int b, float c);

    float myFunction1 (int a, int b, float c)
    {
        return a * b * c;
    }

    float myFunction2 (int a, int b, float c)
    {
        return a + b + c;
    }

    myArrayOfFunctions functions[2];

    myClass()
    {
        functions[0] = &myClass::myFunction1;
        functions[1] = &myClass::myFunction2;
    };

    void Invoke()
    {
        (this->*functions[0])(1, 2, 3);
        (this->*functions[1])(3, 2, 1);
    }
};

int main()
{
    myClass a;
    a.Invoke();
    (a.*(a.functions[0]))(4, 5, 6);
    return 0;
}

As you see, I'm getting the pointer to the class function but to call it I need to call it with an actual object (this in invoke() function and a object in main()).

Marcin Poloczek
  • 923
  • 6
  • 21
  • Thanks for that idea, which I may use. Did you understand I ONLY need to access these functions inside the class itself? – DKDiveDude Mar 15 '20 at 13:12
  • Can’t you call it directly if you only want to access it from inside the class? Is there a point of making an array of functions. – Marcin Poloczek Mar 15 '20 at 13:14
  • The point of making an array of functions, is to save time in an audio processing critical loop that runs 44100 per second, and avoid a bunch of if or switches, and which functions only change when the user change a setting on a knob. In other words when audio processing begins, it is known what function is needed, so there is no need to do time "expensive" if tests or at least waste time, during the main loop. Once the user changes a knob setting, the main loop should just use a different function. – DKDiveDude Mar 15 '20 at 13:22
  • 1
    Got it, but will this be really faster tho? – Marcin Poloczek Mar 15 '20 at 13:23
  • Well that is what I am trying to find out :) I measuring the exact time time in high resolution ticks used in that particular area, so if I get the "array function" idea to work, I'll know exactly if it helps or not. You see I am making a software (vst) synthesizer, and the less time spent in the processing, the more notes (polyphonic) the user can play at any given time. And multiply the 44100 times per second, with 8 tone generators, which each can have up to 16 unison voices, so actually the function needed, may be called up to 5,644,800 times per second, per note played! – DKDiveDude Mar 15 '20 at 13:31
  • Ik that. I have a friend who is working on a voice synthesizer but in python tho. If you want to talk more and share the result of your test feel free to add me on discord RedSkittleFox#7315 – Marcin Poloczek Mar 15 '20 at 13:36
  • @MarcinPoloczek sry you can not simplify `(a.*(a.functions[0]))(4, 5, 6);`. I don't see well your function declaration. – Landstalker Mar 15 '20 at 13:50
  • @MarcinPoloczek I took a break from this, and have NOT implemented a working solution yet, but I did a test release build of code, using all 8 tone generators (oscillators), 16 unison voices, and played 7 notes at once, with a switch, using third case, for each block (1024) of samples, along with displaying signal as a graph and a few others things, it took about 88000 hires ticks. When I copied code in third case up above switch statement, ending with a return skipping switch code, it took about 77000 hires ticks. Test is run 100 times, before spent time is being averaged and displayed – DKDiveDude Mar 15 '20 at 18:39
  • @MarcinPoloczek I successfully implemented your solution, but it is about 14% slower than a switch third case. Again on my synth I am using all 8 tone generators (oscillators), 16 unison voices, and played 7 notes at once. and each block (1024) of samples, along with displaying signal as a graph and a few others things, your implementation took a bit over 100000 hires ticks, compared to a switch which took about 88000 hires ticks. – DKDiveDude Mar 15 '20 at 19:34
  • @DKDiveDude that was to be expected. My solution was just an answer to the question. Also it was to be expected. Switches should be faster than if statements, since compiler can avoid branching with them. My method should be the slowest since it requires a lot of jumps for the processor to make. – Marcin Poloczek Mar 15 '20 at 19:43
  • @MarcinPoloczek A switch when compiled usually uses one if for default, and then jumps for cases. – DKDiveDude Mar 15 '20 at 20:02
  • Not an expert on Lambdas, but I wonder if anything could be done with them, to improve speed. – DKDiveDude Mar 15 '20 at 20:06
0

You can write this:

class myClass
{
public:
    typedef float (*myArrayOfStaticFunctions) (int& a, int& b, float& c);
    typedef float (myClass::*myArrayOfFunctions) (int& a, int& b, float& c);

    static float myFunction1 (int& a, int& b, float& c){cout<<"myFunction1"<<endl; return 0;}
    static float myFunction2 (int& a, int& b, float& c){ cout<<"myFunction2"<<endl; return 0;}
    float myFunction3 (int& a, int& b, float& c){ cout<<"myFunction3"<<endl; return 0;}
    float myFunction4 (int& a, int& b, float& c){ cout<<"myFunction4"<<endl; return 0;}

    myArrayOfStaticFunctions    StaticArrayfunctions[2];
    myArrayOfFunctions          Arrayfunctions[2];

    myClass (){
        StaticArrayfunctions [0] =myFunction1;
        StaticArrayfunctions [1] =myFunction2;
        Arrayfunctions [0] = &myClass::myFunction3;
        Arrayfunctions [1] = &myClass::myFunction4;
    }
};

int _tmain(int argc, _TCHAR* argv[])
{
    myClass m;
    int a =0, b=0; float c;

    m.StaticArrayfunctions[0] (a,b,c);
    m.StaticArrayfunctions[1] (a,b,c);

    myClass::myArrayOfFunctions func3 = m.Arrayfunctions[0];
    myClass::myArrayOfFunctions func4 = m.Arrayfunctions[1];

    (m.*func3)(a,b,c);
    (m.*func4)(a,b,c);

    return 0;
}
Landstalker
  • 1,368
  • 8
  • 9
  • Thank you very much for taking the time to find a solution. I tried to implement static and non-static. I may be misunderstanding something, but the non-static approach seems to defeat the point of my needs, as I have to specifically invoke it by name "func3 or func4" and not a "array number". The static approach is more what I need so I can call the functions like using an array "m.StaticArrayfunctions[0] (a,b,c);", however then the functions can't access the variables declared inside the class, says "a nonstatic member reference must be relative to a specific object" – DKDiveDude Mar 15 '20 at 14:35
  • @DKDiveDude Indeed, but it is aconstraint imposed by static functions in general... See this https://stackoverflow.com/questions/26930108/calling-non-static-variable-from-static-function if you are interested by this topic – Landstalker Mar 15 '20 at 14:50
  • I successfully implemented your static solution, same speed result as Marcin Poloczek's solution, meaning about 14% slower than a switch (see test details below his solution). – DKDiveDude Mar 15 '20 at 20:24
  • @DKDiveDude Ok, please upvote or check "ok" if my solution answered your question ^^ – Landstalker Mar 15 '20 at 20:55