Varadic templates and references as parameters.

Hello,
while working on my Signal & Slot library, I faced a problem with variadic templates and references passed as parameter. Without reference all work very fine (with multiple arguments or without argument at all), but if any of the parameters is a reference, it does return an error at compile time to indicate that it was unable to find the matching constructor.

-- The following code is a very simplified example --

In the following example, DelayedSignal is the class I'm trying to fix and DelayedSignal_DebugHelper is used for debug/comparison purpose. They are almost identical, except the fact that DelayedSignal_DebugHelper use a class template for the third parameter of the last constructor, whereas the DelayedSignal use the method template for this same third argument.

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78

struct DelayedSignal 
{	
	~DelayedSignal ()
	{ std::cout << "~DelayedSignal CLOSE" << std::endl; }
	
	template<class C, class... Args>
	DelayedSignal ( void(C::*func)(Args...), C& obj )
	{ std::cout << "DelayedSignal INIT - 03 - pointer to method & pointer to class instance (Arg num: " << sizeof...(Args) << ")" << std::endl; }
	
	template<class C, class... Args>
	DelayedSignal ( void(C::*func)(Args...), C& obj, Args... args )
	{
		std::cout << "DelayedSignal INIT - 04 - pointer to method & pointer to class instance & arguments (Arg num: " << sizeof...(Args) << ")" << std::endl;
	}
};

template<class... ArgsBis>
struct DelayedSignal_DebugHelper 
{
	~DelayedSignal_DebugHelper ()
	{ std::cout << "~DelayedSignal_DebugHelper CLOSE" << std::endl; }
		
	template<class C, class... Args>
	DelayedSignal_DebugHelper ( void(C::*func)(Args...), C& obj )
	{ std::cout << "DelayedSignal_DebugHelper INIT - 03 - pointer to method & pointer to class instance (Arg num: " << sizeof...(Args) << ")" << std::endl; }
	
	template<class C, class... Args>
	DelayedSignal_DebugHelper ( void(C::*func)(Args...), C& obj, ArgsBis... args ) // Need to use ArgsBis instead of Args to make it work
	{
		std::cout << "DelayedSignal_DebugHelper INIT - 04 - pointer to method & pointer to class instance & arguments (Arg num: " << sizeof...(Args) << ")" << std::endl;
	}
};

template <class Tr> struct Signal;
template <class Tr, class... Args>
struct Signal<Tr(Args...)>
{
	void fire ( Args... args ) { std::cout << "Signal::fire::" << sizeof...(Args) << std::endl;	}
};

struct Klass {};

int main()
{
	std::string str1("Blop");
	Klass k;
	
	Signal<void (Klass&)> signal_01;
	Signal<void (std::string&)> signal_02;
	
	std::cout << "====== DelayedSignal :: needed for production purpose ===============" << std::endl;
	
	// OK
	DelayedSignal test01(&Signal<void (std::string&)>::fire, signal_02);
	// HERE IS THE PROBLEM
	//DelayedSignal test02(&Signal<void (std::string&)>::fire, signal_02, str1);
	
	// OK
	DelayedSignal test03(&Signal<void (Klass&)>::fire, signal_01);
	// HERE IS THE PROBLEM
	//DelayedSignal test04(&Signal<void (Klass&)>::fire, signal_01, k);

	std::cout << "====== DelayedSignal_DebugHelper :: used only for debug purpose ======" << std::endl;
	
	// OK
	DelayedSignal_DebugHelper<std::string&> test05(&Signal<void (std::string&)>::fire, signal_02);
	// OK
	DelayedSignal_DebugHelper<std::string&> test06(&Signal<void (std::string&)>::fire, signal_02, str1);
	
	// OK
	DelayedSignal_DebugHelper<Klass&> test07(&Signal<void (Klass&)>::fire, signal_01);
	// OK
	DelayedSignal_DebugHelper<Klass&> test08(&Signal<void (Klass&)>::fire, signal_01, k);
	
	return 1;
}


Error example:
1
2
main.cpp:2:74: error: no matching function for call to 'DelayedSignal::DelayedSignal(void (Signal<void(std::basic_string<char>&)>::*)(std::basic_string<char>&), Signal<void(std::basic_string<char>&)>&, std::string&)'
main.cpp:57:1: note: candidate is: DelayedSignal::DelayedSignal(const DelayedSignal&)


I was suggested on another forum that it could come from the fact that compiler deduce the same signature for a class instance and a reference to a class instance.
For instance, with test02 (line57), the compiler seems unable to know if "Args..." for the third argument is a std::string or a std::string& despite the fact that it does recognize "Args..." for the first argument.

I would like to be able to store all kinds of DelayedSignal into one std::list. That's why I would like to avoid the DelayedSignal_DebugHelper solution (Using this approach, would lead to use multiple std::list instead of one, and as I suppose that dispatching one list is more optimized than dispatching the undefined number of list required for all kinds of DelayedSignal, I'm trying to avoid this solution). I guess I could use pure virtual class as base class for DelayedSignal too if I want to store all of them into one std::list, but I'm trying to avoid virtual methods too.

Here there a solution to fix this problem ?

Thank you.

Edit : I compile this example using GCC 4.5.0 and the C++0x flag.
Last edited on
Well nobody answered, but as it may interest someone someday; here is a partial solution (still having some problem though).

1
2
3
4
5
template<class C, class... Args>
DelayedSignal ( void(C::*func)(Args&...), C& obj, Args&... args )
{
	std::cout << "DelayedSignal INIT - 04 - pointer to method & pointer to class instance & arguments (Arg num: " << sizeof...(Args) << ")" << std::endl;
}


Using Args&... instead of Args... solve the compiler error problem.
Last edited on
Topic archived. No new replies allowed.