繁体   English   中英

C C ++包装器中的C Variadic函数

[英]C Variadic function in a C++ wrapper

我正在围绕C Python API(Python 1.5)重写一个C包装器,我注意到函数Py_VaBuildValue使用了可变数量的args。 我想知道是否必须在我的C ++函数包装器中使用相同的函数来传递给这个函数,或者是否有更多的C ++方法来处理它?

我知道可变函数可能是造成无法解决的问题的原因,所以如果有更好的方法,我宁愿避免使用它。

编辑:

所以这是我需要在C ++函数中创建的C代码:

int Set_Global(char *modname, char *varname, char *valfmt, ... /* cval(s) */) {

    int result;
    PyObject *module, *val;                             // "modname.varname = val"
    va_list cvals;
    va_start(cvals, valfmt);                            // C args after valfmt

    module = Load_Module(modname);                      // get/load module
    if (module == NULL) 
        return -1;
    val = Py_VaBuildValue(valfmt, cvals);               // convert input to Python
    va_end(cvals);
    if (val == NULL) 
        return -1;
    result = PyObject_SetAttrString(module, varname, val); 
    Py_DECREF(val);                                     // set global module var
    return result;                                      // decref val: var owns it
}

所以我使用std :: string而不是char *制作相同的函数,我想将省略号更改为更像c ++的东西,然后我可以传递给函数内部的Py_VaBuildValue。

如果你想要聪明并且不要担心一些沉重的模板魔法,应该可以生成(或按摩) valfmt以始终匹配你想要传递的类型(我假设它使用类似于printf的格式说明符,但是技术适用于任何类型的格式规范)。 你可以这样做:

template <typename T> struct format_trait;
template <> struct format_trait<int> { static const char * format() { return "%i"; }};
template <> struct format_trait<unsigned> { static const char * format() { return "%u"; }};
... // and so on for each type you want to use

template <typename Arg1>
int Set_Global(const std::string &modname, const std::string &varname, const Arg1 &arg1)
{
    return ::Set_Global(modname.c_str(), varname.c_str(), format_trait<Arg1>::format(), arg1);
}

template <typename Arg1, typename Arg2>
int Set_Global(const std::string &modname, const std::string &varname, const Arg1 &arg1, const Arg2 &arg2)
{
    return ::Set_Global(modname.c_str(), varname.c_str(),
        std::string(format_trait<Arg1>::format()) + format_trait<Arg2>::format(),
        arg1, arg2);
}
... // Repeat up to number of argument you reasonably expect to need or use C++0x variadic templates.

这是一种简单的方法,其中每个值都以默认方式格式化并组合在一起。 如果你想要更复杂的东西,你可以创建一个函数,它将获得valfmt字符串和正确的格式说明符(从特征中获取),并将修复格式字符串以匹配。

您可以编写模板函数来检查参数的正确性,并且不会让您的程序崩溃。

bool BuildValueCheck(const char * s, int v)
{
    if( s[0] == 'i' )
        return true;
    return false;
}
bool BuildValueCheck(const char * s, float v)
{
    if( s[0] == 'f' )
        return true;
    return false;
}
bool BuildValueCheck(const char * s, char * v)
{
    if( s[0] == 's' || s[0] == 'z' )
        return true;
    return false;
}
// and so on for each other type
template<typename t1>
PyObject *BuildValue(char * format, t1 v1)
{
     char * s = strchr(format, "ifsz...."); // Skip here all "()[]" etc
     if( !s )
         return NULL; // and print an error
     if(!BuildValueCheck(s, v1))
         return NULL; // and also print an error
     return Py_BuildValue(format, v1);
}

template<typename t1, typename t2>
PyObject *BuildValue(char * format, t1 v1, t2 v2)
{
     // Skip here all "()[]" etc
     char * s = strchr(format, "ifsz....");
     if( !s )
         return NULL;
     if(!BuildValueCheck(s, v1))
         return NULL;
     s = strchr(s+1, "ifsz....");
     if( !s )
         return NULL;
     if(!BuildValueCheck(s, v2))
         return NULL;
     return Py_BuildValue(format, v1, v2);
}
// and so on for 3,4,5 params - I doubt your program uses more
// and then replace all Py_BuildValue with BuildValue across the code, or make a #define 

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM