构造函数参数的模板参数推断

时间:2013-01-09 15:04:50

标签: c++ templates boost-python template-meta-programming

可以使用以下方式“剥离”函数参数类型:

void foo_double(double a)
{
}

void foo_int(int a)
{

}

template <class R, class A0>
void bar(R (*fp)(A0))
{   
    // Do something related with A0
}

int main()
{
    bar(foo_double); // A0 is double
    bar(foo_int);    // A0 is int
}    

是否可以对类构造函数执行相同的“参数类型剥离”?

编辑:

我相信我没有在原始代码段中清楚地解释自己。这是完整的方案。

我有多个类C1,...,Cn,我需要将它作为函数公开给python。让我们假设所有类都有一个共同的void Run()方法。但是,这些类的构造函数接受不同的参数。要向python公开函数,我使用boost.python,它会在处理所有类型转换(主要是基元)时自动将函数导出到适当的python函数。

我的第一个解决方案是:

class C1 
{
public:
    C1() {}
    void Run();
};

class C2
{
public:
    C2(double a) {}
    void Run();
};

template <class T>
void python_wrapper()
{
    T instance();
    instance.Run();
}

template <class T, class A0>
void python_wrapper(A0 a0)
{
    T instance(a0);
    instance.Run();
}

BOOST_PYTHON_MODULE(_pythonmodule)
{
    // This is boost.python stuff
    python::def("f1", python_wrapper<C1>);
    python::def("f2", python_wrapper<C2, double>);
}

而且......它有效。

我现在要完成的是在推断构造函数参数类型时使用python_wrapper<C2>而不是python_wrapper<C2, double>

正如我在原帖中所展示的那样。如果我要包装函数而不是类,我可以完成类似的事情。

3 个答案:

答案 0 :(得分:0)

您不能获取构造函数的地址(C ++ 98 Standard 12.1 / 12构造函数 - “12.1-12构造函数 - ”不应该使用构造函数的地址。)

如果所有类共享一个基类,那么你可以创建一个工厂,但是没有C ++ 11可变参数模板我不知道如何进行参数转发。

template <typename type>
static type*  construct(){
    return new type();
}


auto value = &construct<int>;

您现在有一个可绑定函数,在调用时会生成类型*

auto value = &construct<int>;
int* newInt = (*value)();
delete newInt;

为了允许不同的构造函数输入,这使用C ++ 11

template <typename type>
class constructor {

public:
    template<typename ...Args>
    static std::shared_ptr<type>  alloc(Args&& ...args){
        return std::shared_ptr<type>(new type(std::forward<Args>(args)...));
    }
    // placement new
    template<typename ...Args>
    static std::shared_ptr<type>  realloc( std::shared_ptr<type>& object,Args&& ...args){
        (new (&(*object)) type(std::forward<Args>(args)...));
        return object;
     }
};

class fooBar{
public:
    fooBar(int x,float f){
    }
};
typedef std::shared_ptr<fooBar> fooBarPtr;

用法:

fooBarPtr a = constructor<fooBar>::alloc(5,0.0f);

或者这可能更接近操作的需要。

class fooy{
    int _x = 0;
public:
    fooy(int argCount, va_list& list){
        if( argCount > 0){
            _x = va_arg(list, int);
        }
    }
};

template <typename type>
std::shared_ptr<type> alloc(int argCount,...) {
    va_list list;
    va_start(list, argCount);
    auto result = std::shared_ptr<type>( new type(argCount,list) );
    va_end(list);
    return result;
}

用法:

auto foo1 = alloc<fooy>(0); // passing zero args
auto foo2 = alloc<fooy>(1,1234); // passing one arg

答案 1 :(得分:0)

由于您不想更改现有的类,因此无法自动化在C ++中对这些类进行演绎。您可以通过从源代码中提取签名信息,在C ++之外为这些类执行此操作。这种提取可以手动完成,也可以通过脚本甚至是C ++程序自动完成。

对于每个现有的类E,使用提取的信息来定义类模板的特化,该类模板定义静态成员函数func,该函数将其参数(如果有的话)传递给类E的构造函数并调用Run方法。

对于新类,只需要他们定义func,并让类模板默认使用现有的func

然后,一般的Python包装器定义代码可以推断出func的参数,你已经告诉它你知道该怎么做。

这意味着定义类的人只需要开始为新的类添加func


稍微高一点,我认为值得利用一些时间让相关人员参与进来,并了解如何通过定义多个类别来采用和巩固一个ungood设计。目标是防止将来再次发生这种情况。我认为,如何应对这种情况取决于它是如何发生的。

答案 2 :(得分:0)

我不确定这将如何与python :: def进行交互,但通常这是可变参数模板的用途:

struct C1{
  C1(){}
  void run(){}
};

struct C2{
  C2(int){}
  void run(){}
};

template<typename CLASS, typename... PARAMS>
void call(PARAMS... params) {
  CLASS inst(params...);
  inst.run();
}

main() {
  call<C1>();
  call<C2>(42);
}

它是c ++ 11,但自4.3版以来在gcc中受支持