3

Here's a simple (and a silly one, yeah) example of what I'm trying to do:

#include <iostream>

void callFunctionsFromAnArray(void *(*)(int), int);
void f1(int);
void f2(int);
void f3(int);

int main()
{
    const int n = 3;
    void (*functions[n]) (int) = { f1, f2, f3 };
    callFunctionsFromAnArray(functions, n);
}

void callFunctionsFromAnArray(void *(*f) (int), int fCount) {
    for (int i = 0; i < fCount; i++)
        f[i](1);
}

void f1(int a)
{
    std::cout << a * 1 << '\n';
}
void f2(int a)
{
    std::cout << a * 2 << '\n';
}
void f3(int a)
{
    std::cout << a * 3 << '\n';
}

And those are the errors I'm getting when trying to compile:

12:9: error: no matching function for call to 'callFunctionsFromAnArray'
        callFunctionsFromAnArray(functions, n);
3:10: note: candidate function not viable: no known conversion from 'void (*[3])(int)' to 'void *(*)(int)' for 1st argument
    void callFunctionsFromAnArray(void *(*)(int), int);
17:13: error: subscript of pointer to function type 'void *(int)'
            f[i](1);
2 errors generated.

However, if I change argument to be void (*f[3]) (int) it works. But the problem is, it's not always possible to know array's size before run-time (that's why function has 2nd argument after all). Is there any solution?

Anhil
  • 65
  • 1
  • 6
  • It's usually a good idea to use `typedef` for function types, to help avoid this problem. – Barmar Dec 15 '13 at 14:11
  • 1
    How about a [`std::vector`](http://en.cppreference.com/w/cpp/container/vector) of [`std::function`](http://en.cppreference.com/w/cpp/utility/functional/function)? – Some programmer dude Dec 15 '13 at 14:11

2 Answers2

3

Since in this case, the array decays into a pointer, you don't have to know its size beforehand -- inside a function argument declaration, and only there, the pointer and the array qualifier (* and []) are equivalent, and the size of the array doesn't matter.

As a result, you can declare your function to take an array of 3 (or however many) pointers, and then you can pass it an array of any pointers:

void callFunctionsFromAnArray(void *(*f[1])(int), int fCount)
{
    for (int i = 0; i < fCount; i++)
        f[i](i);
}

However, if you don't like this, you can just make it accept a pointer-to-pointer:

void callFunctionsFromAnArray(void *(**f)(int), int fCount); // etc.

However, if this really is C++, you'd be better off passing a const reference to a vector of std::functions:

void callFunctionsFromAnArray(const std::vector<std::function<void *(int)> > &a)
{
     // call'em
}
  • +1, although I think it's probably `void (**f) (int)` that's needed, based on the functions being called (I think the OP just misplaced the `*`, essentially). – Oliver Charlesworth Dec 15 '13 at 14:13
  • @OliCharlesworth Sounds reasonable. Let's see what OP actually meant. In the meantime, I've added a more C++-esque solution as well. –  Dec 15 '13 at 14:14
  • is incorrect: "arrays always, unconditionally decay into pointers when passed to a function" – Cheers and hth. - Alf Dec 15 '13 at 14:15
  • @Cheersandhth.-Alf Thanks! What's an exception? –  Dec 15 '13 at 14:15
  • mostly when the formal argument is a reference. oh okay, thinking about it that's the only exception. – Cheers and hth. - Alf Dec 15 '13 at 14:15
  • @Cheersandhth.-Alf That's correct. Amended my answer accordingly. Passionate hate against references increased. –  Dec 15 '13 at 14:16
  • @OliCharlesworth That's right, first time doing this, thought '*' shouldn't be in those parentheses. – Anhil Dec 15 '13 at 14:17
2

Since you are using C++ and not C, I highly suggest you to use std::vector and std::function instead. They will make your life much easier, especially in this particular case:

#include <functional>
#include <vector>

void f1(int);
void f2(int);
void f3(int);

using function_vector = std::vector<std::function<void(int)>>;

void callFunctions(const function_vector& vec) {
    for (const auto& f : vec)
        f(1);
}

int main() {
    function_vector vec = { &f1, &f2, &f3 };
    callFunctions(vec);
}

You can see a live example here.

Shoe
  • 74,840
  • 36
  • 166
  • 272