3

In C++ 11, can I build a template which explicitly instantiates a sequence of function templates into an array initialiser? What I want to achieve (please don't ask why I need that, because it's a long story) looks like

// The template I want to instantiate:
template<size_t N> void callbackTemplate(const int dummy) {
    // Do something which needs to know 'N'.
}

// The variable I want to assign 'callbackTemplate' instantiations to:
void (*callback)(const int dummy);  // This cannot be std::function, because it 
                                    // is not defined by me! It is already there and 
                                    // must be used as it is.

// This is the set of instantiations I want to prepare:
std::array<decltype(callback), 3> callbackTemplates = {
    callbackTemplate<0>, callbackTemplate<1>, callbackTemplate<2>
};

The code above works as it is. What I want to change is the initialisation of the callbackTemplates array. I want the initialiser to become a template which is dependent on a compile-time constant and creates the instantiations 0..N.

The problem is somehow related to C++ static const array initialization in template class, but I did not manage to "templatise" the instantiation of the other template.

Community
  • 1
  • 1
Christoph
  • 1,964
  • 2
  • 27
  • 44

3 Answers3

2

You can do this using an implementation of C++14's std::integer_sequence. Here's one.

With callback_t defined as

using callback_t = decltype (callback);

you can just pass a sequence and make use of the type deduction:

template<unsigned... Is>
array<callback_t, sizeof...(Is)> make_callback_array_impl(seq<Is...>)
{
    return { callbackTemplate<Is>... };
}

template<unsigned N>
array<callback_t, N> make_callback_array()
{
    return make_callback_array_impl(GenSeq<N>{});
}

live demo

Community
  • 1
  • 1
krzaq
  • 16,240
  • 4
  • 46
  • 61
2

This can be done with variable template specializations.

template<class>
int callbackTemplates_v;

template<std::size_t... Indicies>
std::array<decltype(callback), sizeof...(Indicies)>
  callbackTemplates_v<std::index_sequence<Indicies...>> = {callbackTemplate<Indicies>...};

template<std::size_t N>
auto callbackTemplates = callbackTemplates_v<std::make_index_sequence<N>>;

Now callbackTemplates<N> is an array of N instaniations of callbackTemplate from 0..N-1.

David G
  • 94,763
  • 41
  • 167
  • 253
0

Do you mean something as follows?

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 <std::size_t N>
struct arrayWrapper
 {
   private:
      std::array<decltype(callback), N>  callBT;

      template <std::size_t ... rng>
      arrayWrapper (const range<rng...> &)
         : callBT{ callbackTemplate<rng>... }
       { }

   public:
      arrayWrapper () 
         : arrayWrapper (typename rangeH<N>::type())
       { }
 };

If you can use C++14, you can throw away rangeH and range and the wrapper become simply

template <std::size_t N>
struct arrayWrapper
 {
   private:
      std::array<decltype(callback), N>  callBT;

      template <std::size_t ... rng>
      arrayWrapper (const std::index_sequence<rng...> &)
         : callBT{ callbackTemplate<rng>... }
       { }

   public:
      arrayWrapper () 
         : arrayWrapper (std::make_index_sequence<N>())
       { }
 };
max66
  • 65,235
  • 10
  • 71
  • 111