确定类构造函数参数的数量和类型(C++?

Determine the number and type of the class constructor's parameters in C++?

本文关键字:类型 C++ 构造函数 参数      更新时间:2023-10-16

如何确定类构造函数参数的数量和类型?对于成员函数执行此操作只是小菜一碟:

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及其确切原型的数据库。我需要基于此生成一些存根。

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

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

现在绑定器函数很简单:

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

我会建议解决此问题的方法。我经常使用"静态实例构造函数"模式 - 例如,用于反序列化类的实例,该类是子类化的,例如。

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<> 和 lambda。我想,它们可能会使您的架构更简单。