0

Is it possible to write a variadic template class

template<typename Functor, int... D>
struct Foo
{
    void bar()
    {
        // ???
    }
};

Which is equivalent to

template<typename Functor, int D0>
struct Foo<Functor, D0>
{
    void bar()
    {
        Functor f;
        double d0[D0];
        f(d0);
    }
};

template<typename Functor, int D0, int D1>
struct Foo<Functor, D0, D1>
{
    void bar()
    {
        Functor f;
        double d0[D0];
        double d1[D1];
        f(d0, d1);
    }
};

// And so on...

That is, the number of arguments to pass to the functor is equal to the number of template arguments. The arguments should be allocated on the stack.

Petter
  • 37,121
  • 7
  • 47
  • 62

3 Answers3

5

Following a version with the arguments on the stack through a std::tuple:

// Helper class to be able to use expansion of std::get<Index>(tuple)
template <int... Is> struct index_sequence {};

// Following create index_sequence<0, 1, 2, .., sizeof...(Is) - 1>
template <int Index, int... Is>
struct make_index_sequence { // recursively build a sequence of indices
    typedef typename make_index_sequence<Index - 1, Index -1, Is...>::type type;
};

template <int... Is>
struct make_index_sequence<0, Is...> { // stop the recursion when 0 is reached
    typedef index_sequence<Is...> type;
};

template<typename Functor, int... Ds>
struct Foo
{
    void bar()
    {
        bar(typename make_index_sequence<sizeof...(Ds)>::type());
    }
private:
    template <int... Is>
    void bar(index_sequence<Is...>)
    {
        Functor f;
        std::tuple<double[Ds]...> t; // std::tuple<doudle[D0], double[D1], ..>
        f(std::get<Is>(t)...);       // f(std::get<0>(t), std::get<1>(t), ..);
    }
};
Jarod42
  • 203,559
  • 14
  • 181
  • 302
  • a really nice implementation. – Koushik Shetty Dec 28 '13 at 04:14
  • the technique that you have used decdue the types and use the no of types decduced as `Indices` in `get<>` right? could you explain this a bit? i have difficulty wrapping my head around the `indices` expansion. it would be great if you could post an edit with the explanation. thanks a lot :-) – Koushik Shetty Dec 28 '13 at 05:20
  • the Indices expansion is a technique to *iterate* over `std::tuple`. you may look at http://stackoverflow.com/questions/16387354/template-tuple-calling-a-function-on-each-element. – Jarod42 Dec 28 '13 at 09:36
  • oh my because of a slight misread, it took me a lot of time to understand your code(the zero specialization code). the misread was this `struct indices<0, Indices...> { typedef indices type;} ` part where i was **not** realizing you were **not** invoking `::type` on `indices` which made me recuse till `indices<>`(leads to error). i was kicking myself :-) – Koushik Shetty Dec 28 '13 at 10:46
  • Interesting technique. Thanks! – Petter Dec 28 '13 at 15:02
2

Is that what you want?

template<typename Functor, int... D>
struct Foo
{
    template<std::size_t N>
    std::array<double, N> create()
    {
       return std::array<double, N>();
    }

    void bar()
    {
       Functor f;
       f(create<D>()...);
    }
};
ForEveR
  • 55,233
  • 2
  • 119
  • 133
  • clean and simple solution IMHO. but the OP asked for a slightly different thing, apart from unpacking to the functor he also wants a local copy of each array. – Koushik Shetty Dec 28 '13 at 03:52
0

Maybe this works:

template <typename Functor, int i, int... others>
struct Foo
{
  template <typename ...T>
  void bar(T ... rest)
  {
    double d[i];
    Foo<Functor, others...> foo;
    foo.bar(rest..., d);
  }
};

template <typename Functor, int i>
struct Foo<Functor, i>
{
  template <typename ...T>
  void bar(T ... rest)
  {
    double d[i];
    Functor f;
    f(d, rest...);
  }
};
user1781290
  • 2,674
  • 22
  • 26