我需要计算
D
维函数的函数值和梯度,并将这些值加在一起。我认为将梯度部分简单地存储在第一个 D
分量中,并将函数的值存储在 D+1
维向量的最后一个分量中,这在计算上是有益的。
但是,如何从
D
维向量中提取第一个 D+1
分量(即梯度部分)?我知道有切片选项,但我不想在这里添加任何无意义的开销。所以,我试着简单地在我的reinterpret_cast<Eigen::Vector<T, D>&>
上做一个Eigen::Vector<T, D + 1>
并且它起作用了;但这真的能保证工作(并且安全)吗?
它会导致未定义的行为。
只有当泛左值的类型与对象的类型similar 时,您才可以通过泛左值使用类的成员。 相似表示类型相同到
const
资格。
当你像这样使用
reinterpret_cast
时,你改变了左值的类型,但你仍然让它引用与原始类型相同的对象。 (如果在同一地址有一个目标类型的对象与原始对象是pointer-interconvertible,则有一些例外,但我怀疑是否可以保证
Eigen::Vector
以这样的方式实现
Eigen::Vector<T, D+1>
是标准布局,其开头包含一个
Eigen::Vector<T, D>
子对象,这是应用例外的先决条件。)即使您不那么关心 UB,至少您也在对这两个类的内存布局做出假设。但是没有人保证你的布局。 (不过,就算保底了,还是有UB的。)
你不需要切片操作,你想要块操作
。大多数(全部?)它们都带有模板版本。如果
D
是运行时变量,要获取向量的前
D
元素,请调用
vector.head(D)
。如果它是一个编译时常量,使用
vector.head<D>()
.返回的 block 表达式对象类似于 Eigen Map
,因为它实际上是一个零开销引用,并且完全按照您的意愿行事。// act like reference
auto first_d = vector.head<D>();
// copy into new vector
auto copy = first_d.eval();
// or
Eigen::Vector<double, D> copy2 = first_d;
中使用
auto
的常见警告适用,但这种用法是可以的。如果您想安全起见,请拼出类型或不要将其作为变量保留,仅将其用作表达式的一部分。
如果您在没有
-DNDEBUG
的情况下进行编译,将会进行范围检查,除非编译器可以将其优化掉(模板参数可能就是这种情况)。
回到最初的问题:不,这不安全。即使您相信 Eigen 永远不会改变固定大小类型的内部布局(合理的假设),较小的向量可能会有更大的对齐。
alignof(Vector3d) < alignof(Vector2d)
。这将导致 Eigen 创建假定更高对齐的机器指令(例如 x86 上的 movapd
与 movupd
),这将在运行时失败。