How could one determine the number and type of the class constructor's parameters? To do that for a member function is just a piece of cake:
template <class T, typename P0, typename P1, typename P2, typename P3>
void BindNativeMethod( void (T::*MethodPtr)(P0, P1, P2, P3) )
{
// we've got 4 params
// use them this way:
std::vector<int> Params;
Params.push_back( TypeToInt<P0>() );
Params.push_back( TypeToInt<P1>() );
Params.push_back( TypeToInt<P2>() );
Params.push_back( TypeToInt<P3>() );
}
template <class T, typename P0, typename P1, typename P2, typename P3, typename P4>
void BindNativeMethod( void (T::*MethodPtr)(P0, P1, P2, P3, P4) )
{
// we've got 5 params
// use them this way:
std::vector<int> Params;
Params.push_back( TypeToInt<P0>() );
Params.push_back( TypeToInt<P1>() );
Params.push_back( TypeToInt<P2>() );
Params.push_back( TypeToInt<P3>() );
Params.push_back( TypeToInt<P4>() );
}
and so on for other members.
But what to do with the class constructors? Is there any way to find out the type of their arguments? Maybe there's a fundamentally different approach to solve this because it's even impossible to take the address of the constructor?
Edit: I have a C++ preprocessor that scans all source files and has the database of all classes, methods, ctors and their exact prototypes. I need to generate some stubs based on this.
If I understand your requirement correctly, you want a function that you can take the address of that tells you the types of the parameters to the constructor or constructors.
#include <string>
#include <new>
template <typename T, typename P0, typename P1>
T * fake_ctor (T *mem, P0 p0, P1 p1) {
return mem ? new (mem) T(p0, p1) : 0;
}
struct Foo {
Foo (int, int) {}
Foo (int, std::string) {}
};
template <class T, typename P0, typename P1>
void BindClassCtor(T *(*FakeCtor)(T *, P0, P1)) {
std::vector<int> Params;
Params.push_back( TypeToInt<P0>() );
Params.push_back( TypeToInt<P1>() );
}
// PARSER GENERATED CALLS
BindClassCtor<Foo, int, int>(&fake_ctor);
BindClassCtor<Foo, int, std::string>(&fake_ctor);
Implementing the fake_ctor
to actually invoke the ctor
(even though fake_ctor
itself will never be called) provides a level of compile time sanity. If Foo
changes one of the constructors without regenerating the BindClassCtor
calls, it will likely result in a compile time error.
Edit: As a bonus, I simplified parameter binding using templates with variadic arguments. First, the BindParams
template:
template <typename... T> struct BindParams;
template <typename T, typename P0, typename... PN>
struct BindParams<T, P0, PN...> {
void operator () (std::vector<int> &Params) {
Params.push_back( TypeToInt<P0>() );
BindParams<T, PN...>()(Params);
}
};
template <typename T>
struct BindParams<T> {
void operator () (std::vector<int> &Params) {}
};
Now, fake_ctor
is now a collection of classes, so that each can be instantiated by a variadic parameter list:
template <typename... T> struct fake_ctor;
template <typename T>
class fake_ctor<T> {
static T * x (T *mem) {
return mem ? new (mem) T() : 0;
}
decltype(&x) y;
public:
fake_ctor () : y(x) {}
};
template <typename T, typename P0>
class fake_ctor<T, P0> {
static T * x (T *mem, P0 p0) {
return mem ? new (mem) T(p0) : 0;
}
decltype(&x) y;
public:
fake_ctor () : y(x) {}
};
template <typename T, typename P0, typename P1>
class fake_ctor<T, P0, P1> {
static T * x (T *mem, P0 p0, P1 p1) {
return mem ? new (mem) T(p0, p1) : 0;
}
decltype(&x) y;
public:
fake_ctor () : y(x) {}
};
And now the binder function is simply this:
template <typename... T>
void BindClassCtor (fake_ctor<T...>) {
std::vector<int> Params;
BindParams<T...>()(Params);
}
Below is an illustration of the constructor argument bindings for Bar
that has four constructors.
struct Bar {
Bar () {}
Bar (int) {}
Bar (int, int) {}
Bar (int, std::string) {}
};
BindClassCtor(fake_ctor<Bar>());
BindClassCtor(fake_ctor<Bar, int>());
BindClassCtor(fake_ctor<Bar, int, int>());
BindClassCtor(fake_ctor<Bar, int, std::string>());