2

如何确定类构造函数参数的数量和类型?为成员函数做到这一点只是小菜一碟:

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>() );
}

等等其他成员。

但是如何处理类构造函数呢?有没有办法找出他们论点的类型?也许有一种根本不同的方法来解决这个问题,因为甚至不可能获取构造函数的地址?

编辑:我有一个 C++ 预处理器,它扫描所有源文件并拥有所有类、方法、ctor 及其确切原型的数据库。我需要基于此生成一些存根。

4

2 回答 2

5

如果我正确理解您的要求,您需要一个可以获取地址的函数,该函数可以告诉您构造函数或构造函数的参数类型。

#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);

实现fake_ctor以实际调用ctor(即使它fake_ctor本身永远不会被调用)提供了一定程度的编译时健全性。如果Foo更改其中一个构造函数而不重新生成BindClassCtor调用,则可能会导致编译时错误。

编辑:作为奖励,我使用带有可变参数的模板简化了参数绑定。一、BindParams模板:

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) {}
};

现在,fake_ctor现在是一个类的集合,这样每个类都可以通过可变参数列表进行实例化:

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) {}
};

现在 binder 函数就是这样的:

template <typename... T>
void BindClassCtor (fake_ctor<T...>) {
    std::vector<int> Params;
    BindParams<T...>()(Params);
}

Bar下面是具有四个构造函数的构造函数参数绑定的说明。

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>());
于 2012-07-25T06:00:38.020 回答
1

我会建议解决此问题的方法。我经常使用“静态实例构造函数”模式——例如反序列化一个类的实例,它是子类的,例如。

class BaseClass
{
private:
    BaseClass();
    virtual void InternalLoad(MyStream s) = 0;

public:
    static BaseClass * Create(MyStream s);
};

(...)

BaseClass * BaseClass::Create(MyStream s);
{
    int type;
    s >> type;

    if (type == 0)
    {
        BaseClass * result = new DerivedClass1(); // DerivedClass1 : public BaseClass
        result->InternalLoad(s);
        return result;
    }
    else if (type == 1)
    ...
}

您可以轻松地在您的情况下使用此模式。只需创建一个静态实例构造函数,它是通用的并以您希望的方式处理其参数。


编辑:

我认为,您可以通过以下方式解决问题:

class MyClass
{
private:
    MyClass();

public:
    template <typename T1, typename T2>
    static MyClass * Create(T1 t, T2 u);
};

(...)

template <typename T1, typename T2>
MyClass * MyClass::Create(T1 t, T2 u)
{
    MyClass result = new MyClass();
    // Process parameters t and u here
    return result;
}

然后你可以通过以下方式构建类:

MyClass* class = MyClass::Create(5, "Indiana Jones");

请注意,这不是一个解决方案,而是(我认为非常优雅)解决方法。


编辑:

我想,我现在明白了,您正在尝试做的事情以及使用静态方法而不是构造函数实际上仍然可以证明是解决您的问题的方法(但这取决于您要如何处理有关构造函数参数的信息)。

显然,您应该使用常规参数实现静态构造函数,如下所示:

class MyClass
{
private:
    MyClass();

public:
    static MyClass * Create(int t, char * u);
};

您应该能够检索指向静态函数的指针并将其传递给您的工具方法。


编辑:

既然你解释了,你真的想做什么,我建议使用类工厂(首选)或静态构造函数,如前所述。这样,您始终可以检索指向所需方法(静态或非静态)的指针,并在当前架构中使用它(基于您提供的代码)。

另外,看看 C#/11 中的 std::function<> 和 lambdas。我想,它们可能会使您的架构变得更简单。

于 2012-07-23T05:57:54.693 回答