如何解决具有某些公共成员的强制转换结构
假设我有 2 个struct
:
typedef struct
{
uint8_t useThis;
uint8_t u8Byte2;
uint8_t u8Byte3;
uint8_t u8Byte4;
} tstr1
和
typedef struct
{
uint8_t u8Byte1;
uint8_t u8Byte2;
uint8_t useThis;
} tstr2
我将只需要函数内的 useThis
成员,但在某些情况下,我需要强制转换一个或另一个结构:
void someFunction()
{
someStuff();
SOMETHING MyInstance;
if(someVariable)
{
MyInstance = reinterpret_cast<tstr1*>(INFO_FROM_HARDWARE); //This line of course doesn't work
}
else
{
MyInstance = reinterpret_cast<tstr2*>(INFO_FROM_HARDWARE); //This line of course doesn't work
}
MyInstance->useThis; //Calling this memeber with no problem
moreStuff();
}
-
所以我想使用
useThis
无论做了什么演员。这怎么办? -
我想避免
someFunction()
成为模板(只是为了避免 this kind of things) -
注意像 this 这样的问题有一种类似的问题,但结构成员有相同的顺序
编辑:
在 RealLife 中,这些结构体要大得多,并且有几个“同名”成员。直接将 uint8_t
转换为 reinterpret_cast<tstr1*>(INFO_FROM_HARDWARE)->useThis
会很乏味,并且需要几个 reinterpret_cast
(虽然这是我在此编辑之前的问题的有效解决方案)。这就是我坚持MyInstance
“完整”的原因。
解决方法
这就是模板的用途:
template<class tstr>
std::uint8_t
do_something(std::uint8_t* INFO_FROM_HARDWARE)
{
tstr MyInstance;
std::memcpy(&MyInstance,INFO_FROM_HARDWARE,sizeof MyInstance);
MyInstance.useThis; //Calling this memeber with no problem
// access MyInstance within the template
}
// usage
if(someVariable)
{
do_something<tstr1>(INFO_FROM_HARDWARE);
}
else
{
do_something<tstr2>(INFO_FROM_HARDWARE);
}
我想避免 someFunction() 成为模板(只是为了避免这种事情)
为什么我不能将模板类的定义与其声明分开并将其放入 .cpp 文件中?
链接问题对您的用例来说不是问题,因为潜在的模板参数集是一个有限集。下一个常见问题解答 entry 解释了如何: 使用模板的显式实例。
,按照 AndyG 的建议,std::variant
怎么样(没有提到您正在使用的 c++ 标准,所以也许 c++17 解决方案是可以的 - 如果没有 c+,也值得使用 +17 可用)。
这是一个example
std::variant
知道其中存储的是什么类型,并且您可以随时使用访问来使用其中的任何成员(为了清楚起见,请在此处摘录):
// stolen from @eerrorika (sorry for that :( )
struct hardware {
uint8_t a = 'A';
uint8_t b = 'B';
uint8_t c = 'C';
uint8_t d = 'D';
};
struct tstr1 {
uint8_t useThis;
uint8_t u8Byte2;
uint8_t u8Byte3;
uint8_t u8Byte4;
};
struct tstr2 {
uint8_t u8Byte1;
uint8_t u8Byte2;
uint8_t useThis;
};
// stuff
if(true)
{
msg = *reinterpret_cast<tstr1*>(&hw);
}
else
{
msg = *reinterpret_cast<tstr2*>(&hw);
}
std::visit(overloaded {
[](tstr1 const& arg) { std::cout << arg.useThis << ' '; },[](tstr2 const& arg) { std::cout << arg.useThis << ' '; }
},msg);
编辑:你也可以做一个指针的变体 EDIT2:忘记转义一些东西...
,对结构成员的简单引用可能就是您所需要的:
uint8_t &useThis=SomeVariable
?reinterpret_cast<tstr1*>(INFO_FROM_HARDWARE)->useThis
:reinterpret_cast<tstr2*>(INFO_FROM_HARDWARE)->useThis;
,
在映射到硬件时,使用 virtual
调度通常不是您想要的,但它是一种替代方法。
示例:
// define a common interface
struct overlay_base {
virtual ~overlay_base() = default;
virtual uint8_t& useThis() = 0;
virtual uint8_t& useThat() = 0;
};
template<class T>
class wrapper : public overlay_base {
public:
template<class HW>
wrapper(HW* hw) : instance_ptr(reinterpret_cast<T*>(hw)) {}
uint8_t& useThis() { return instance_ptr->useThis; }
uint8_t& useThat() { return instance_ptr->useThat; }
private:
T* instance_ptr;
};
有了它,您可以声明一个基类指针,分配它,并在 if
语句之后使用:
int main(int argc,char**) {
std::unique_ptr<overlay_base> MyInstance;
if(argc % 2) {
MyInstance.reset( new wrapper<tstr1>(INFO_FROM_HARDWARE) );
} else {
MyInstance.reset( new wrapper<tstr2>(INFO_FROM_HARDWARE) );
}
std::cout << MyInstance->useThis() << '\n';
std::cout << MyInstance->useThat() << '\n';
}
关于我的评论的解释:“它可以工作,但是除非编译器非常聪明并且可以优化内部循环中的虚拟分派,否则它会比您实际花时间进行类型转换要慢":
将 virtual
分派视为在运行时使用的查找表 (vtable)(这通常是实际发生的情况)。在调用 virtual
函数时,程序必须使用该查找表来查找要调用的实际成员函数的地址。当无法优化查找时(正如我在上面的示例中通过使用仅在运行时可用的值确保的那样),与通过静态转换获得的相比,它确实需要额外的几个 CPU 周期。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。