parameter pack in a template class

Jul 19, 2011 at 10:01pm
Hello and sorry for my probably bad english,
I'm working on a pacman-like game, in C++0x ( because I want variadic templates ) , and I'm trying to make a template class around the SDL ( Simple Directmedia Layer, a game library ) timers. for people who don't know SDL, there are the two SDL functions related to the SDL timers :
 
SDL_TimerID SDL_AddTimer(Uint32 interval, Uint32 (*callback)(Uint32, void*), void *param);

This function tells the SDL to run the function pointed by the argument "callback" after "interval" milliseconds. This function gets two arguments, first, the "interval", and second, the void pointer "param", which can point on everything.
It ( the function ) must return a number in milliseconds, and it is re-run after this time. If it returns 0, it is never re-run.
 
void SDL_RemoveTimer(SDL_TimerID id)

When you create a timer with SDL_AddTimer, it returns a SDL_TimerID ( a simple typedef of int, or something, IMHO ) which can be passed to this function to stop the timer previousely created by SDL_AddTimer. It does nothing if the timer's function already returned 0.

I'm trying to make a template which takes a functor and a parameter pack, and uses a SDL timer to run this functor with an unsigned int ( the interval ) and the parameter pack as arguments after a specified time. The functor must return an unsigned int, which is used like the return of the function of an SDL timer.
I tried with an attribute :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
timer.hpp

#include <SDL/SDL.h>

template <typename Functor, typename... Args>
class Timer
{
	public:
	Timer (unsigned int interval, Functor functor, Args... args):m_functor(functor), m_args(args)
	{
		m_timerID = SDL_AddTimer(interval, Call, this);
	}
	~Timer ()
	{
		SDL_RemoveTimer(m_timerID);
	}
	private:
	static Uint32 Call(Uint32 interval, void* that)
	{
		return (*(Timer*)that).m_functor(interval, (*(Timer*)that).m_args);
	}
	Functor m_functor;
	Args... m_args;
	SDL_TimerID m_timerID;
};

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
test.cpp

#include <iostream>
#include <functional>

#include "timer.hpp"

unsigned int sayHello(unsigned int)
{
	using namespace std;
	cout << "hello world\n" << endl;
	return 0;
}
int main()
{
	SDL_Init(SDL_INIT_TIMER);
	Timer<std::function<unsigned int(unsigned int)>> timer(15, sayHello);
	SDL_Delay(25); //sleep for 25 milliseconds, to allow the timer to be executed.
}

g++ says :

In file included from test.cpp:4:0:
timer.hpp:21:6: error: expected unqualified-id before ‘...’ token
timer.hpp: In constructor ‘Timer<Functor, Args>::Timer(unsigned int, Functor, Args ...)’:
timer.hpp:7:83: error: class ‘Timer<Functor, Args>’ does not have any field named ‘m_args’
timer.hpp: In static member function ‘static Uint32 Timer<Functor, Args>::Call(Uint32, void*) [with Functor = std::function<unsigned int(unsigned int)>, Args = {}, Uint32 = unsigned int]’:
timer.hpp:9:3:   instantiated from ‘Timer<Functor, Args>::Timer(unsigned int, Functor, Args ...) [with Functor = std::function<unsigned int(unsigned int)>, Args = {}]’
test.cpp:15:69:   instantiated from here
timer.hpp:18:68: error: ‘class Timer<std::function<unsigned int(unsigned int)> >’ has no member named ‘m_args’

I saw the following code in the C++0x standard :
1
2
3
4
5
template<class... Mixins>
class X : public Mixins... {
public:
X(const Mixins&... mixins) : Mixins(mixins)... { }
};

X inherits from its parameter pack, let's try :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
timer.hpp

#include <SDL/SDL.h>

template <typename Functor, typename... Args>
class Timer: public Args...
{
	public:
	Timer (unsigned int interval, Functor functor, Args... args):m_functor(functor), Args(args)...
	{
		m_timerID = SDL_AddTimer(interval, Call, this);
	}
	~Timer ()
	{
		SDL_RemoveTimer(m_timerID);
	}
	private:
	static Uint32 Call(Uint32 interval, void* that)
	{
		return (*(Timer*)that).m_functor(interval, (*(Args*)that));
	}
	Functor m_functor;
	SDL_TimerID m_timerID;
};

then :

In file included from test.cpp:4:0:
timer.hpp: In static member function ‘static Uint32 Timer<Functor, Args>::Call(Uint32, void*)’:
timer.hpp:18:60: error: parameter packs not expanded with ‘...’:
timer.hpp:18:60: note:         ‘Args’

When I add an ellipsis after the right "Args" :

In file included from test.cpp:4:0:
timer.hpp: In static member function ‘static Uint32 Timer<Functor, Args>::Call(Uint32, void*)’:
timer.hpp:18:53: error: expected primary-expression before ‘...’ token
timer.hpp:18:53: error: expected ‘)’ before ‘...’ token
timer.hpp:18:64: error: expected ‘)’ before ‘;’ token

There is my "g++ --version" :

g++ (Debian 4.6.1-1) 4.6.1
Copyright (C) 2011 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.


Is it possible with the current C++0x draft ? If yes, How ? If not, is it planned in a future draft ? please help me.
Jul 19, 2011 at 10:59pm
Have you looked at std::bind yet? This seems like it would solve your problem and eliminate the need for variadic templates in your code. It is still C++0x, but the use of variadic templates are hidden away in the C++ standard library's std::bind implementation.

Jul 20, 2011 at 1:03pm
Thank you PanGalactic, the following code compiles :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
timer.hpp

#include <functional>

template <typename... Args>
class Timer
{
	public:
		Timer (unsigned int interval, std::function<unsigned int(unsigned int, Args...)> functor, Args... args)
		{
			m_callback = bind(functor, std::placeholders::_1, args...);
			m_timerID = SDL_AddTimer(interval, Call, this);
		}
		~Timer ()
		{
			SDL_RemoveTimer(m_timerID);
		}
	private:
		static Uint32 Call(Uint32 interval, void* that)
		{
			return (*(Timer*)that).m_callback(interval);
		}
		std::function<unsigned int(unsigned int)> m_callback;
		SDL_TimerID m_timerID;
};

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
test.cpp

#include <iostream>

#include "timer.hpp"

unsigned int sayHello(unsigned int)
{
	using namespace std;
	cout << "Hello world!" << endl;
	return 0;
}
int main()
{
	SDL_Init(SDL_INIT_TIMER);
	Timer<> timer(15, sayHello);
	SDL_Delay(25); //sleep for 25 milliseconds, to allow the timer to be executed.
}

The result is obviousely :
Hello world!
Topic archived. No new replies allowed.