Reputation: 457
The CUDA 7 standard regarding variadic global function templates states "only a single pack parameter is allowed." Is there an elegant workaround for this? I want to be able to do something like:
template<int... vals>
void RecursiveFunct() {
}
template<int... vals, typename T, typename... Args>
void RecursiveFunct(T t, Args... args) {
t.template call<vals...>();
RecursiveFunct<vals...>(args...);
}
I'm thinking I could wrap my pack of integers into something before passing them along but is it possible to do that in a way that is transparent to the caller of this code?
Upvotes: 4
Views: 212
Reputation: 66210
Not sure to understand your exactly limits but... I suppose that std::integer_sequence
and a wrapper function to call call()
can help you.
The following is a toy, but compilable, example that show what I mean.
struct foo
{
template <int ... vals>
void call () const
{ std::cout << "- call " << sizeof...(vals) << std::endl; }
};
template <typename IS>
void RecursiveFunct (IS const &)
{ }
template <typename T, int ... vals>
void wrapCall (T const & t, std::integer_sequence<int, vals...> const &)
{ t.template call<vals...>(); }
template<typename IS, typename T, typename ... Args>
void RecursiveFunct (IS const & is, T t, Args... args)
{
wrapCall(t, is);
RecursiveFunct(is, args...);
}
int main ()
{
// print 5 times "- call 4"
RecursiveFunct(std::integer_sequence<int, 2, 3, 5, 7>{},
foo{}, foo{}, foo{}, foo{}, foo{});
}
Take in count that std::integer_sequence
is a C++14 feature, so the preceding code needs (at least) a C++14 compiler.
But if you need to work with C++11, it's trivial to create a std::integer_sequence
substitute.
By example
template <typename T, T ... ts>
struct myIntegerSequence
{ };
-- EDIT --
The OP ask
can this work without creating an instance of integer_sequence?
In normal C++14, yes. Works this with Cuda? I don't know.
I've obtained this changing the wrapCall()
func with a wrapCall
struct and a func()
static method. This because I've used the partial specialization that can't be used with funcs.
The folling is the toy example
#include <utility>
#include <iostream>
struct foo
{
template <int ... vals>
void call () const
{ std::cout << "- call " << sizeof...(vals) << std::endl; }
};
template <typename>
void RecursiveFunct ()
{ }
template <typename>
struct wrapCall;
template <int ... vals>
struct wrapCall<std::integer_sequence<int, vals...>>
{
template <typename T>
static constexpr void func (T const & t)
{ t.template call<vals...>(); }
};
template<typename IS, typename T, typename ... Args>
void RecursiveFunct (T t, Args... args)
{
wrapCall<IS>::func(t);
RecursiveFunct<IS>(args...);
}
int main ()
{
// print 5 times "- call 4"
RecursiveFunct<std::integer_sequence<int, 2, 3, 5, 7>>
(foo{}, foo{}, foo{}, foo{}, foo{});
}
But are you sure that is a problem the istantiation of a std::integer_sequence
?
Upvotes: 3