matrix of function pointers

K

Klaas Vantournhout

Hi all,

I'm in need of a matrix of function pointers, and to be honest. No
'nice' solution has been found yet on that big big internet.

It is possible to declare a matrix of function pointers in the following
way

void (*f[2][2])(int);

But I want to know how I can declare this only using double pointers.
like an array

double **a;
a = new double *[2];
for (int i = 0; i < 2; i++)
a = new double [2];

I would like to know this, because I have in my code something which is
similar like below, and i want it to work. The problem is, that during
compiling i obtain the following error.

cannot convert 'void (* (*)[2])(int)' to 'void (***)(int)' for argument
'1' to 'void pm_funcion(void (***)(int), int)'
cannot convert 'void (* (*)[3])(int)' to 'void (***)(int)' for argument
'1' to 'void pm_funcion(void (***)(int), int)'

thanks in advance

klaas


//function
void pm_function(void (***f) (int), int dim) {
for (int i = 0; i < dim; i++)
for (int j = 0; j < dim; j++)
f[j](5);
}

int main(void) {
void (*f[2][2])(int);
void (*g[3][3])(int);
// I want this to work, but it doesn not! See error above message
pm_function(f,2);
pm_function(g,3);

}
 
B

benben

Maybe the following code would help:

typedef void (*fnptr)(int);
typedef fnptr** fnptr_mtrx;

fnptr_mtrx matrix = ...
 
J

John Carson

Klaas Vantournhout said:
Hi all,

I'm in need of a matrix of function pointers, and to be honest. No
'nice' solution has been found yet on that big big internet.

It is possible to declare a matrix of function pointers in the
following way

void (*f[2][2])(int);

But I want to know how I can declare this only using double pointers.
like an array

double **a;
a = new double *[2];
for (int i = 0; i < 2; i++)
a = new double [2];

I would like to know this, because I have in my code something which
is similar like below, and i want it to work. The problem is, that
during compiling i obtain the following error.

cannot convert 'void (* (*)[2])(int)' to 'void (***)(int)' for
argument '1' to 'void pm_funcion(void (***)(int), int)'
cannot convert 'void (* (*)[3])(int)' to 'void (***)(int)' for
argument '1' to 'void pm_funcion(void (***)(int), int)'

thanks in advance

klaas


//function
void pm_function(void (***f) (int), int dim) {
for (int i = 0; i < dim; i++)
for (int j = 0; j < dim; j++)
f[j](5);
}

int main(void) {
void (*f[2][2])(int);
void (*g[3][3])(int);


You realise of course that you have never initialised these function
pointers to point to anything.
// I want this to work, but it doesn not! See error above message
pm_function(f,2);
pm_function(g,3);

}

Your problem is not specifically with function pointers. You would have the
same problem with arrays of ints, e.g., the following won't compile for the
same reason.

void pm_function(int **pptr, int dim)
{
for (int i = 0; i < dim; i++)
for (int j = 0; j < dim; j++)
cout << pptr[j];
}

int main()
{
int arraytwo[2][2];
int arraythree[3][3];

pm_function(arraytwo,2);
pm_function(arraythree,3);

return 0;
}

Array names and pointers are only (more or less) interchangeable when the
array is one dimensional (in the sense of having a single subscript). For
two and more dimensions (in the sense of two or more subscripts) they are
quite different.

To illustrate, if pptr points to an int pointer, then pptr+1 is an address
that is sizeof(int*) greater than pptr. By contrast, using the definition of
arraythree given above, arraythree+1 yields an address that is 3*sizeof(int)
greater than the address of arraythree. The difference is because pptr
points to an int* pointer, whereas arraythree points to a row of three ints.

To prove it, run the following code:

int main()
{
int x;
int *ptr = &x;
int **pptr = &ptr;
cout << "pptr address is " << pptr << '\n';
cout << "pptr+1 address is " << pptr+1 << '\n';

int arraythree[3][3];

cout << "arraythree address is " << arraythree << '\n';
cout << "arraythree+1 address is " << arraythree+1 << '\n';


return 0;
}

If you want to pass 2-dimensional arrays to a function, then you need to a
different function for each different column count. Templates can help here.
 
K

Klaas Vantournhout

//function
void pm_function(void (***f) (int), int dim) {
for (int i = 0; i < dim; i++)
for (int j = 0; j < dim; j++)
f[j](5);
}

int main(void) {
void (*f[2][2])(int);
void (*g[3][3])(int);


You realise of course that you have never initialised these function
pointers to point to anything.


Yes I do ;-)

Your problem is not specifically with function pointers. You would have the
same problem with arrays of ints, e.g., the following won't compile for the
same reason.
> If you want to pass 2-dimensional arrays to a function, then you need to a
different function for each different column count. Templates can help here.

I am indeed aware of this. That is why I would like to define my matrix
of function pointers using dynamical allocation using the new operator.
This should sort that problem out and let me use a double pointer in
the function call.

The answer given by benben is indeed a solution. But I was wondering if
you could do it without defining a new type.

Already thanks for your swift response.

klaas
 
K

Klaas Vantournhout

benben said:
Maybe the following code would help:

typedef void (*fnptr)(int);
typedef fnptr** fnptr_mtrx;

fnptr_mtrx matrix = ...


Thanks benben for the swift response,

But is this possible without redefining a new type?

In your declaration fnptr_mtrx is indeed of the type void (***)(int);

using your declartion I would be able to do
fnptr_mtrx = new fnptr *[n];
for (int i = 0; i < n; i++)
fnptr = new fnptr [m];

to construct an n x m function pointer matrix, but is it possible to
write something like

void (***g)(int);
g = new void (**)(int) *[5];

or anything like that? (the above does not work)

klaas
 
J

JoShCrUz

I think you should go back to basics, first the work out the pointers
to functions:

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <iostream>
#include <cstdlib>

using namespace std;
//-----------------------------------------------------------------------------
// define the type
typedef void (*Tpointer2Function)(int);
// define the array with 3 elements
Tpointer2Function ArrayOfFunctions[3];
//-----------------------------------------------------------------------------
void function1(int a)
{
cout << "function 1 = " << a << endl;
}
//-----------------------------------------------------------------------------
void function2(int a)
{
cout << "function 2 = " << a << endl;
}
//-----------------------------------------------------------------------------
void function3(int a)
{
cout << "function 3 = " << a << endl;
}
//-----------------------------------------------------------------------------
int main(int argc, char *argv[])
{
// assign the functions you want to call to the array
ArrayOfFunctions[0] = function1;
ArrayOfFunctions[1] = function2;
ArrayOfFunctions[2] = function3;
// iterate thru the array
for (int i=0; i <=2; i++)
{
ArrayOfFunctions(i);
}
return EXIT_SUCCESS;
}
//-----------------------------------------------------------------------------

Once you've done that you could go and have a dynamic array (see Bruce
Eckel's 'thinking in c++' 2nd edition - "Arrays of pointers to
functions" section - with minor modifications):

#include <iostream>
#include <cstdlib>

using namespace std;
//-----------------------------------------------------------------------------
// A macro to define dummy functions - Bruce's functions have no int
parameter;
#define DF(N) void N(int a) { cout << "function " #N " called with
parameter " << a << endl; }

DF(a); DF(b); DF(c); DF(d); DF(e); DF(f); DF(g);

void (*func_table[])(int) = {a, b, c, d, e, f, g};
//-----------------------------------------------------------------------------
int main(int argc, char *argv[])
{
while (true)
{
char c, cr;
cout << "press a key from 'a' to 'g' or 'q' to quit" << endl;
cin.get(c); cin.get(cr); // second one for CR
// another alteration LValues are better there so you don't get
assignments
// rather than comparisons
if ('q'== c)
break;
if (c < 'a' || c > 'g')
continue;
(*func_table[c - 'a'])(101);
}
return EXIT_SUCCESS;
}
//-----------------------------------------------------------------------------
 
J

John Carson

Klaas Vantournhout said:
I am indeed aware of this. That is why I would like to define my
matrix of function pointers using dynamical allocation using the new
operator. This should sort that problem out and let me use a double
pointer in the function call.

The answer given by benben is indeed a solution. But I was wondering
if you could do it without defining a new type.

Already thanks for your swift response.

klaas

A typedef does not introduce a new type. It is simply an alias for a type.

You can do dynamic allocation of function pointers without using a typedef,
but it is pointlessly difficult to do so.

Just for the record:

#include <iostream>

using namespace std;

// function to which function pointers will point
template<int n>
void func(int x)
{
cout << n*x << '\n';
}

// your (modified) function
void pm_function(void (*(*(*f)))(int), int dim)
{
for (int i = 0; i < dim; i++)
for (int j = 0; j < dim; j++)
f[j](5);
}



int main()
{
// dynamic pointer allocation

void (*(*(*g)))(int) = new (void (*(*[3]))(int));

for(int i=0; i<3; ++i)
g = new (void (*[3])(int));

// initialise function pointers
for(int i=0; i<3; ++i)
{
for(int j=0; j<3; ++j)
{
switch(i)
{
case 0:
g[j]=&func<0>;
break;
case 1:
g[j]=&func<1>;
break;
case 2:
g[j]=&func<2>;
break;
}
}
}

// test your function
pm_function(g,3);

// cleanup

for(int i=0; i<3; ++i)
delete[] g;

delete[] g;

return 0;
}

If you think this is good code, then we have very different ideas of what
constitutes good code.
 
K

Klaas Vantournhout

A typedef does not introduce a new type. It is simply an alias for a type.

Indeed, my mistake there
You can do dynamic allocation of function pointers without using a typedef,
but it is pointlessly difficult to do so.

Just for the record:

void (*(*(*g)))(int) = new (void (*(*[3]))(int));

for(int i=0; i<3; ++i)
g = new (void (*[3])(int));


If you think this is good code, then we have very different ideas of what
constitutes good code.

Why should this not be good code? I dislike the use of typedef because
it makes things sometimes unreadable. It is to my opinion only usefull
when you have an extreme long annoying type which you have to declare
multiple times.

Here this is not the case, you can see immediately of what type 'g' is.
And it is not much more difficult then using a typedef. The
initialisation is done in the same way.

Or did you mean something else?

I used this in my code because I could reduce 300 lines of code to only
20 with this. Removed a big mixture of case and if conditions which was
totally unreadable. And also the size of the matrix depends on the
initial conditions of my program.

Thanks again for the answer. You made my day!

klaas
 
J

John Carson

Klaas Vantournhout said:
A typedef does not introduce a new type. It is simply an alias for a
type.

Indeed, my mistake there
You can do dynamic allocation of function pointers without using a
typedef, but it is pointlessly difficult to do so.

Just for the record:

void (*(*(*g)))(int) = new (void (*(*[3]))(int));

for(int i=0; i<3; ++i)
g = new (void (*[3])(int));


If you think this is good code, then we have very different ideas of
what constitutes good code.

Why should this not be good code? I dislike the use of typedef
because it makes things sometimes unreadable. It is to my opinion
only usefull when you have an extreme long annoying type which you
have to declare multiple times.

Here this is not the case, you can see immediately of what type 'g'
is.



I doubt that 1 in 100 C++ programmers can "see immediately what type g is".
I couldn't do so myself if I hadn't written the code.

Compare:

typedef void (*FnPtr)(int);

FnPtr **g = new FnPtr*[3];

for(int i=0; i<3; ++i)
g = new FnPtr[3];

Once you make the typedef, this looks just like what you would do if you had
an array of ints or doubles. It is familiar and easy to comprehend.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,777
Messages
2,569,604
Members
45,232
Latest member
DorotheaDo

Latest Threads

Top