键入来自不同第三方库的两种类型,无需联合
Type punning two types from different third party libraries without union
我读到使用联合进行类型双关语实际上是C++中未定义的行为,我想知道您将如何键入双关语?
例如,我使用联合来键入来自两个具有相同布局的第三方库的双关语两种类型(libAQuaternion 和 libBQuaternion 是我无法更改的第三方库的类型(:
struct libAQuaternion {
double x, y, z, w;
};
void libAFunc(libAQuaternion &p) {
p.x = p.y = p.z = p.w = 1.;
}
struct libBQuaternion {
double x, y, z, w;
};
void libBFunc(libBQuaternion &p) {
p.x = p.y = p.z = p.w = 2.;
}
union myQuat {
libAQuaternion a;
libBQuaternion b;
};
int main() {
myQuat q;
libAFunc(q.a);
libBFunc(q.b);
}
符合最佳解决方案的标准是什么?
符合此标准的最佳解决方案是什么?
编写一个函数以从一个四元数转换为另一个四元数。
libBQuaternion convert(const libAQuaternion &Quat) {
return{Quat.x, Quat.y, Quat.z, Quat.w};
}
libAQuaternion convert(const libBQuaternion &Quat) {
return{Quat.x, Quat.y, Quat.z, Quat.w};
}
// or template if you want to
template<typename T, typename U>
T convertTo(U &&Quat) {
return{Quat.x, Quat.y, Quat.z, Quat.w};
}
任何优化器都应该能够完全优化这一点,因此不应该有性能损失。
但是,如果有一个函数通过左值引用获取一个这样的类,这将是一个问题。您需要创建适当类的新对象,传递该对象,然后将正确的值重新分配给原始结构。我想你可以为此创建一个函数,但 IMO 最干净的方法是更改函数的签名以通过左值 ref 获取单个值,但这并不总是可能的。
如果不调用 UB,就无法在C++中进行类型双关语。
C++不允许类型双关语。大多数时候。
你写的东西是完全合法的,但有一个潜在的危险。
这两个四元数是标准布局类,它们共同的初始序列是它们的整体。 因此,通过工会阅读另一方的成员是合法
的myQuat q = libAQuaternion{1, 0, 0, 0};
std::cout << q.b.x; // legal
然后我们注意到,四元数只能通过内置/琐碎赋值或放置 new 来写入。
对非活动成员(或其成员,递归方式(使用内置/简单赋值会导致非活动成员生存期的隐式开始。
使用新展示位置也将开始成员的生命周期。
因此,在写入四元数时,它的生命周期要么已经开始,要么将开始。
读取和写入一起称为访问,严格别名规则禁止访问具有另一种类型的内容,这是禁止类型双关的原因。但是,由于我们刚刚证明了访问任一四元数是明确定义的,因此这是类型双关语确实合法的一个例外。
一个危险是当库函数部分写入四元数时
void someFunc(libBQuaternion& q)
{
q.x = 1;
}
myQuat q = libAQuaternion{1, 0, 0, 0};
someFunc(q.b);
std::cout << q.a.y; // UB
不幸的是,q.a.y
是未初始化的,因此读取它是未定义的行为。
但是,考虑到所有以前的规则以及未初始化变量背后的原因是效率,编译器不太可能利用 UB 和"错误编译"。
template<class D, class S>
D bitcpy( S const* s ){
static_assert( sizeof(S)>=sizeof(D) );
D r;
memcpy( &r, s, sizeof(D) );
return r;
}
union myQuat {
libAQuaternion a;
libBQuaternion b;
void AsA(){
a = bitcpy<libAQuaternion>(&b);
}
void AsB(){
b = bitcpy<libBQuaternion>(&a);
}
};
您必须跟踪工会中是否有A
或B
。 切换呼叫AsA
或AsB
;这是运行时的Noop。
我相信工会规则允许通过分配来激活成员;如果我误解了标准或情况(这些是豆荚类型吧?(,事情会变得更加棘手。 但我认为这不适用于这里。
键入双关语的最安全方法是使用从类型 A 到 B 类型的memcpy
。在许多平台上,memcpy
是一个内在的含义,它是由编译器实现的,因此很可能被优化掉。
- 如何使映射键具有两种不同的数据类型?
- 如何构造可以调用和返回两种不同类型的模板
- std::cin 从控制台获取两种不同的变量类型,'storing'以后使用第二种类型?
- C++ 一个函数,可以根据接受的值返回两种类型之一
- C++指针中的这两种类型的值分配有什么区别?
- 有没有办法让C++函数采用具有相同成员的两种不同类型?
- C++两种类型相互依赖
- 生成一个类Name_class并将两种数据类型存储在一个向量中
- 两种类型的构造函数重载
- 没有使用两种类型的字符串进行匹配的函数调用
- 声明具有两种类型的变量:"int char"
- 使用 Arduino 发送两种不同类型的传感器数据
- 键入来自不同第三方库的两种类型,无需联合
- 给定这两种类型,我是否可以确定虚拟函数是否已被覆盖?
- 如何使用指针连接两种不同的节点类型(结构)?
- 如何获得将两种不同类型的相乘的结果类型?
- 尝试连接两种不同类型的结构来创建链表
- 声明"t"中的两种或多种数据类型
- 如何获得C - 模板状行为,但仅允许实例化两种特定类型
- 为什么 c++ 编译器在对两种不同类型的数值变量使用"std::max()"函数时会出现错误