在 C++ 中将非指定类型作为参数传递的最佳方法?



所以我目前正在为一些嵌入式系统编写一个抽象层。我通常用 C 语言这样做,但我想看看我是否可以在某些C++中学习一点。

我遇到了一个问题,因为我试图抽象出一个 Usart 类。hw init 需要有特定于硬件的参数,所以我正在努力在 cpp 中做到这一点。在 C 中,我可以传递一个 void 指针并将 void 参数转换为我选择的类型,但由于某种原因,我不能在C++中执行此操作。我也想象有一种更好的方法来做到这一点,C++更安全,所以如果可能的话,我想走这条路。在编译时而不是运行时通过或失败真的很酷。这是我到目前为止的想法:

#include <iostream>
#include <cstdint>
class Usart
{
public:
Usart(){}
~Usart(){}
virtual int configure(void* hw_args)
{
if(hw_args == NULL)
{
return -1;
}
}
private:
};
class mcu1_Usart : public Usart
{
public:
mcu1_Usart(){}
~mcu1_Usart(){}
struct config
{
uint32_t pin1;
uint32_t pin2;
uint32_t pin3;
uint32_t pin4;
};
virtual int configure(void* hw_args)
{
config* conf = (config*)hw_args;
// do hardware stuff with config
return 0;
}
};
class mcu2_Usart : public Usart
{
public:
mcu2_Usart(){}
~ mcu2_Usart(){}
struct config
{
uint32_t pin1;
uint32_t pin2;
uint32_t pin3;
uint32_t pin4;
uint32_t pin5;
};
virtual int configure(void* hw_args)
{
config* conf = (config*)&hw_args;
// do hardware stuff with config

return 0;
}
};

int main()
{
Usart _usart;
mcu1_Usart::config conf;
_usart.configure((void*)conf);
}

这不会编译。它说它无法将 void* 转换为 mcu1_Usart::config。有没有更好的方法可以做到这一点?我真的希望它在编译时通过/失败,所以在这里使用函数指针作为配置 init 不是最佳的,但如果C++没有办法做到这一点,我理解。

编辑:我忘了说 &conf 而不是 conf。所以这确实可以编译。但是,我想知道是否有更好的方法来做到这一点C++因为这种方式相当不安全。

我认为您要做的是拥有一个类似"必须有一个返回int并接受适当配置结构的configure方法"之类的接口,类实现必须实现它才能编译代码。

如果为 true,则可以使用奇怪的重复出现的模板模式和类型比较来确保configure方法存在并具有正确的签名。这仍然会使用继承,但我们将摆脱configure方法virtual,从而避免无用的 vtable 条目(甚至 vtable 本身(。

下面的示例使用 C++17,因此请务必在编译器中打开此语言版本。

#include <type_traits>
#include <iostream>
#include <cstdint>
template<typename Derived>
class Usart
{
public:
Usart()
{
// This will check that there exists a method "configure" that matches
// the signature we want.
static_assert(std::is_same_v<decltype(&Derived::configure),
int (Derived::*)(typename Derived::config const&)>);
}
};
class mcu1_Usart : public Usart<mcu1_Usart>
{
public:
mcu1_Usart(){}
~mcu1_Usart(){}
struct config
{
uint32_t pin1;
uint32_t pin2;
uint32_t pin3;
uint32_t pin4;
};
int configure(config const& conf)
{
// do hardware stuff with config
return 0;
}
};
class mcu2_Usart : public Usart<mcu2_Usart>
{
public:
mcu2_Usart(){}
~mcu2_Usart(){}
struct config
{
uint32_t pin1;
uint32_t pin2;
uint32_t pin3;
uint32_t pin4;
uint32_t pin5;
};
int configure(config const& conf)
{
// do hardware stuff with config
return 0;
}
};
int main()
{
mcu1_Usart _usart;
mcu1_Usart::config conf;
_usart.configure(conf);
}

要测试编译时检查,请尝试添加一个无关的参数,例如mcu2_Usart::configure,或更改其返回值,甚至完全删除该方法。你会得到编译失败,而上面未更改的代码编译成功(在线尝试(。

最新更新