在c++中用void* 参数 Package 第三方库c函数的推荐方法?

hrirmatl  于 2022-11-27  发布在  其他
关注(0)|答案(1)|浏览(138)

我有一个与硬件接口的第三方封闭源码c库,该库有一些api函数,它们接受void *参数来读/写和配置一些io,如下所示:

int iocall(int cmd, void * args);
int iorw(int cmd, void * buff, size_t buff_size);

我想把这些封装在一个c++类中,以便能够注入该类,能够使用gtest模拟它,引入异常,并在上层服务类中消除所有返回值检查。到目前为止一切顺利。下面是我的问题:当涉及到void *参数时,为该类设计接口的最佳方法是什么?
interface.h

class wrap:
{
    virtual void wrap_iocall(int cmd, ??) = 0;
}

interface_impl.h

class wrap:
{
    void wrap_iocall(int cmd, ??) override
    {
        int ret{iocall(cmd, ??)};
        // do some more stuff, e.g. exceptions and so on
    }
}

我的第一步是用专用类型重载调用-但由于有很多专用类型,这可能是一个维护的痛苦,当需要另一个调用时(例如,其他硬件调用),我将需要更改接口+库可能会得到更新,这迫使我更新类型。
我考虑的第二件事是使用std::any,这将适合我的用例,但我不确定如何将指向std::any容器的指针传递给底层c函数?我考虑将其推入std::vector<std::any>,并使用.data()函数传递指针。但是,然后我就只剩下一个猜测的大小,我认为容器?这听起来像一个非常糟糕的尝试,以实现我正在寻找的。
我遇到的第三件事是一个使用模板的解决方案,但如果我的理解是正确的,这些东西不可能是虚拟的,因此打破了我的意图,模拟界面,要求它是虚拟的。所以我认为这可能也行不通。
目前我能想到的最后一件事是在 Package 函数中坚持只使用void *,并让上层服务层处理类型转换,例如为特定的设备调用分配struct,并将指针传递到 Package 器的void *参数。这是目前为止我最不喜欢的选项。
我想坚持类型安全函数参数的原则,但我不确定如何从这里继续下去。任何帮助/反馈都是非常感谢的!

64jmpszr

64jmpszr1#

我不确定我是否正确地理解了你的需求。然而,似乎你自己也不确定你需要什么:)
因此,我提出了一个基于模板和参数包的解决方案,希望这个例子能让你了解可以做些什么。

#include <iostream>

// My mockups of production and test funcions
int iocall(int cmd, ...){
    va_list vl;
    va_start(vl, cmd);
    std::cout << "iocall cmd=" << cmd;
    for(int x = 0; x < cmd; ++x) 
        std::cout << " " << va_arg(vl, void*);
    std::cout << "\n";
    return 0;
};

int iotest(int cmd, ...){
    va_list vl;
    va_start(vl, cmd);
    std::cout << "testcall cmd=" << cmd;
    for(int x = 0; x < cmd; ++x)
        std::cout << " " << va_arg(vl, void*);
    std::cout << "\n";
    return 0;
};

// Wrappers
struct do_iocall {
    template <typename... Args>
    int operator()(int cmd, Args... args) 
        { return iocall(cmd, static_cast<void*>(args)...); }
};

struct do_testcall {
    template <typename... Args>
    int operator()(int cmd, Args... args) 
        { return iotest(cmd, static_cast<void*>(args)...); }
};

// Pseudo-main class of application
template <class T>
class BigEngine {
    T wrapper;
public:
    int RunEverything(){
        struct One {} one;
        struct Two {} two;

        wrapper(1, &one);
        wrapper(2, &one, &two);
        return 0;
    }
};

int main()
{
    // Production run
    BigEngine<do_iocall> prod;
    prod.RunEverything();

    // Test run
    BigEngine<do_testcall> test;
    test.RunEverything();
    return 0;
}

https://godbolt.org/z/eqbz8s6oe

相关问题