Given a set of functions, such as:
template<class A1>
Void Go(A1 a);
template<class A1, class A2> Void Go(A1 a1, A2 a2);
template<class A1, class A2, class A3> Void Go(A1 a1, A2 a2, A3 a3); Is it possible to take an array of some variant type and given its contents, fire the correct function? My application for this is that I want to pass a set of parameters X, to another process, where I only have the option of passing a single pointer. My idea was to send a pointer to a std::vector<boost::any> and then to somehow work out which of the above methods to fire given its contents.
This concerns my experiments with cross-thread eventing and communication, hence it may seem unnecessarily esoteric!
Edit: ok, for example, this is the intention. Obviously it doesn't compile (the template resolution occurs at compile-time, but I want to determine which function to call at run-time!):
#include <boost\any.hpp>
#include <vector>
#include <iostream>
#include <string>
class A
{
public:
void Go()
{
std::cout << L"(0 params)\n";
}
template
void Go(U0 u0)
{
std::cout << L"1 param " << u0 << L"\n";
}
template
void Go(U0 u0, U1 u1)
{
std::cout << L"2 params " << u0 << L" " << u1 << L"\n";
}
template
void Go(U0 u0, U1 u1, U2 u2)
{
std::cout << L"3 params " << u0 << L" " << u1 << L" " << u2 << L"\n";
}
};
class B
{
public:
void Whatever() {}
};
int main(int argc, wchar_t* argv[])
{
// Create a collection of variants.
std::vector<boost::any> myVariants;
B myB;
myVariants.push_back(123);
myVariants.push_back(std::wstring(L"Test"));
myVariants.push_back(&myB);
// Take a void pointer to them.
void *variants = &myVariants;
// Convert back into an array.
std::vector<boost::any>& myConverted = *(std::vector<boost::any> *)(variants);
// Fire the correct event on A.
A myA;
switch(myConverted.size())
{
case 0:
myA.Go();
break;
case 1:
myA.Go(myConverted[0]);
break;
case 2:
myA.Go(myConverted[0], myConverted[1]);
break;
case 3:
myA.Go(myConverted[0], myConverted[1], myConverted[2]);
break;
default: ;
// throw
}
}
Ok, I made some progress with this. If I use an array of boost::any, I can convert to and from a void * (and hence pass it as an lParam in a custom window message to a msgProc). The solution is if both sender and receiver classes have the same template parameters. That is to say, something like this (should compile as a console project in 2010):
#include <boost\any.hpp>
#include <vector>
#include <iostream>
#include <string>
// A class to receive the event.
template<typename A0 = int, typename A1 = int, typename A2 = int>
class A
{
public:
void Go()
{
std::wcout << L"(0 params)\n";
}
void Go(A0 u0)
{
std::wcout << L"1 param " << u0 << L"\n";
}
void Go(A0 u0, A1 u1)
{
std::wcout << L"2 params " << u0 << L" " << u1 << L"\n";
}
void Go(A0 u0, A1 u1, A2 u2)
{
std::wcout << L"3 params " << u0 << L" " << u1 << L" " << u2 << L"\n";
}
};
// A class to demonstrate passing an abitrary object.
class B
{
public:
};
// Implement operator on type B so we can use std::cout.
std::wostream& operator << (std::wostream& o, const B& b)
{
o << L"Hello!";
return o;
}
// A class that converts an array of boost::any from void and calls an appropriate function on A.
template<typename A0 = int, typename A1 = int, typename A2 = int>
class C
{
public:
void Everything()
{
// Create a collection of variants.
std::vector<boost::any> myVariants;
B myB;
myVariants.push_back(123);
myVariants.push_back(myB);
// Take a void pointer to them.
void *variants = &myVariants;
// Convert back into an array.
std::vector<boost::any>& myConverted = *(std::vector<boost::any> *)(variants);
// Fire the correct event on A.
A<A0, A1, A2> myA;
switch(myConverted.size())
{
case 0:
myA.Go();
break;
case 1:
myA.Go(boost::any_cast<A0>(myConverted[0]));
break;
case 2:
myA.Go(boost::any_cast<A0>(myConverted[0]), boost::any_cast<A1>(myConverted[1]));
break;
case 3:
myA.Go(boost::any_cast<A0>(myConverted[0]), boost::any_cast<A1>(myConverted[1]), boost::any_cast<A2>(myConverted[2]));
break;
default: ;
// throw
}
}
};
int main(int argc, wchar_t* argv[])
{
C<int, B> c;
c.Everything();
}
The above demonstrates going from a vector of boost::any to a void * and then back to a vector of boost::any, calling a function on some object with the correct arity and types.