1

Given a function pointer array of function_sig, I want to initialise it to a set of template function pointers that are index via a template parameter. Is this possible?

E.g.

template<int I>
void fn() { /* do something */ }

typedef void(*function_sig)();

template<int ARRAY_SIZE>
struct items
{
  static function_sig array[ARRAY_SIZE];
};

template<int ARRAY_SIZE>
function_sig items<ARRAY_SIZE>::array = { /* what do I put here? */ };

So, is there something that I can put in the initialiser list, such that items<ARRAY_SIZE>::array will be initialised to { fn<0>, fn<1>, ..., fn<ARRAY_SIZE-1> }?

NOTE: I know of a way to do this with preprocessor magic, but I'd like to try without that. Currently, I'm thinking I'll have to do away with the array and replace it with something that would act like an array, but that would lead to a search of O(N) when indexing the pseudo-array, which I'd like to not do.

2

2 Answers 2

1

The problem is to get a variadic range from 0 to ARRAY_SIZE - 1.

I propose a solution that transfer array in a base class itemsH

#include <iostream>


template <std::size_t ...>
struct range
 { };

template <std::size_t N, std::size_t ... Next>
struct rangeH 
 { using type = typename rangeH<N-1U, N-1U, Next ... >::type; };

template <std::size_t ... Next >
struct rangeH<0U, Next ... >
 { using type = range<Next ... >; };


template<int I>
void fn() { std::cout << "[" << I << "]" << std::endl; }

typedef void(*function_sig)();

template <typename T>
struct itemsH;

template <std::size_t ... RNG>
struct itemsH<range<RNG...>>
 {
   static function_sig array[sizeof...(RNG)];
 };

template<std::size_t ARRAY_SIZE>
struct items : public itemsH<typename rangeH<ARRAY_SIZE>::type>
 { };

template <std::size_t ... RNG>
function_sig itemsH<range<RNG...>>::array[sizeof...(RNG)] = { fn<RNG>... };


int main ()
 {
   items<10>  i_10;

   for ( unsigned ui = 0U ; ui < 10 ; ++ui )
      i_10.array[ui]();

   return 0;
 }

p.s.: I've changed the type of ARRAY_SIZE from int to size_t; hoping isn't a problem

p.s.2: sorry for my bad English.

--- edit: added C++14 example ---

If you (when you) can use C++14, the you can use std::index_sequence and std::make_index_sequence, throwing away range and rangeH.

The example become

#include <utility>
#include <iostream>


template<int I>
void fn() { std::cout << "[" << I << "]" << std::endl; }

typedef void(*function_sig)();

template <typename T>
struct itemsH;

template <std::size_t ... RNG>
struct itemsH<std::index_sequence<RNG...>>
 { static function_sig array[sizeof...(RNG)]; };

template<std::size_t ARRAY_SIZE>
struct items : public itemsH<std::make_index_sequence<ARRAY_SIZE>>
 { };

template <std::size_t ... RNG>
function_sig itemsH<std::index_sequence<RNG...>>::array[sizeof...(RNG)]
   = { fn<RNG>... };


int main ()
 {
   items<10>  i_10;

   for ( unsigned ui = 0U ; ui < 10 ; ++ui )
      i_10.array[ui]();

   return 0;
 }
Sign up to request clarification or add additional context in comments.

1 Comment

Your English is fine and the switch to std::size_t is fine. I only used int because I was lazy. :D I would usually use std::size_t.
0
#include <array>

template<int... Is>
struct int_seq { };

namespace detail {

template<int I, int... Is>
struct make_int_seq : make_int_seq<I - 1, I, Is...> { };

template<int... Is>
struct make_int_seq<0, Is...> {
    using type = int_seq<0, Is...>;
};

} // namespace detail

template<int SizeN>
using make_int_seq = typename detail::make_int_seq<SizeN - 1>::type;

template<int I>
void fn() { /* do something */ }

//typedef void(*function_sig)();
using function_sig = void(*)();

template<int ARRAY_SIZE>
struct items {
    static std::array<function_sig, ARRAY_SIZE> array;
};

template<int... Is>
std::array<function_sig, sizeof...(Is)> create_items_array(int_seq<Is...>) {
    return {{ &fn<Is>... }};
}

template<int ARRAY_SIZE>
std::array<function_sig, ARRAY_SIZE> items<ARRAY_SIZE>::array
  = create_items_array(make_int_seq<ARRAY_SIZE>{});

Online Demo

With C++14, int_seq et al disappear in favor of std::integer_sequence et al.

3 Comments

@Adrian : No, C-arrays are not copyable and thus cannot be returned from functions, and we need the create_items_array factory function.
FYI, some slight modification would have to be made with upgrading to c++14, as your make_int_seq will generate 0..N, where as std::make_integer_sequence generates 0..N-1.
@Adrian : No, it doesn't, and I've no idea why you think it would...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.