0

For an embedded solution I want to define an array of void(*relay)(void) functions which I use as callback relays for a library which only accepts stateless void(*f)(void) callbacks. The relays will then call the actual std::function callbacks.

The code below works nicely. However, I'm looking for a possibility to change the number of relay functions without having to manually type their initialization to the array. A compile time solution would be nice but initialization of the array at runtime would be fine as well.

Any chance to implement such a thing in C++?

constexpr size_t nrOfRelays = 5;

std::function<void(void)> cb[nrOfRelays]; // callbacks

void (*const relays[nrOfRelays])(void)    // array of pointers to void(*relay)(void)
{
    [] { cb[0](); },
    [] { cb[1](); },
    [] { cb[2](); },
    [] { cb[3](); },
    [] { cb[4](); },
};

void test(unsigned nr, std::function<void(void)> callback)
{
    cb[nr] = callback;
    attachCallback(nr, relays[nr]); // lib requires a void(*f)() callback
}
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
luni64
  • 321
  • 2
  • 8

1 Answers1

1

I don't think it's possible with a plain array. You'll need to use something like std::array to be able to return it from a helper function/lambda.

Here's a C++20 solution with a lambda template:

constexpr std::array<void(*)(), nrOfRelays> relays =
    []<std::size_t ...I>(std::index_sequence<I...>) {
        return std::array<void(*)(), nrOfRelays>{[]{cb[I]();}...};
    }(std::make_index_sequence<nrOfRelays>{});

And here's a C++17 one with a helper function:

template <std::size_t ...I>
constexpr std::array<void(*)(), nrOfRelays> MakeRelays(std::index_sequence<I...>)
{
    return std::array<void(*)(), nrOfRelays>{[]{cb[I]();}...};
}

constexpr auto relays = MakeRelays(std::make_index_sequence<nrOfRelays>{});

The second solution can be used in C++14 if you replace the lambda with a template function:

template <std::size_t I> void helper() {cb[I]();}

template <std::size_t ...I>
constexpr std::array<void(*)(), nrOfRelays> MakeRelays(std::index_sequence<I...>)
{
    return std::array<void(*)(), nrOfRelays>{helper<I>...};
}

constexpr auto relays = MakeRelays(std::make_index_sequence<nrOfRelays>{});
HolyBlackCat
  • 78,603
  • 9
  • 131
  • 207
  • I tried the C++17 version which works perfectly. But I can't figure out how to implement the proposed change for the C++14 version. Mind to show the changed code? – luni64 Sep 03 '20 at 19:50