简体   繁体   English

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

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

I am rewriting a C wrapper around a C Python API (Python 1.5) and I noticed that the function Py_VaBuildValue uses variadic number of args. 我正在围绕C Python API(Python 1.5)重写一个C包装器,我注意到函数Py_VaBuildValue使用了可变数量的args。 I wondered if I have to use the same in my C++ function wrapper to pass to this function or if there is a more C++ way to deal with this? 我想知道是否必须在我的C ++函数包装器中使用相同的函数来传递给这个函数,或者是否有更多的C ++方法来处理它?

I know variadic functions can be the cause of untold trouble, so I'd rather avoid having to use if there is a better way. 我知道可变函数可能是造成无法解决的问题的原因,所以如果有更好的方法,我宁愿避免使用它。

EDIT: 编辑:

So here is the C code I need to make into a C++ function: 所以这是我需要在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
}

So I'm making the same function with std::string instead of char* and I want to change the ellipsis to something more c++ like, that I can however then pass to Py_VaBuildValue inside the function. 所以我使用std :: string而不是char *制作相同的函数,我想将省略号更改为更像c ++的东西,然后我可以传递给函数内部的Py_VaBuildValue。

If you want to be clever and don't fear some heavy template wizardry, it should be possible to generate (or massage) valfmt to always match the types you want to pass (I am assuming it uses format specifiers similar to printf, but the technique is applicable to any kind of format specification). 如果你想要聪明并且不要担心一些沉重的模板魔法,应该可以生成(或按摩) valfmt以始终匹配你想要传递的类型(我假设它使用类似于printf的格式说明符,但是技术适用于任何类型的格式规范)。 You could do something like: 你可以这样做:

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.

This is the simple way where each value is formatted the default way and combined together. 这是一种简单的方法,其中每个值都以默认方式格式化并组合在一起。 If you want something more complex, you can create a function, that will get valfmt string and correct format specifiers (obtained from the trait) and will fix up the format string to match. 如果你想要更复杂的东西,你可以创建一个函数,它将获得valfmt字符串和正确的格式说明符(从特征中获取),并将修复格式字符串以匹配。

You may write template function which will check the correctness of params, and won't allow your program to crash. 您可以编写模板函数来检查参数的正确性,并且不会让您的程序崩溃。

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