从不同的库中隐式转换相似类型以在 C++ 中无缝地协同工作
Implicit casting similar types from separate libraries to work together seamlessly together in C++
我正在使用 GLM 和 Bullet Physics,它们都有自己的矢量类型 - glm::vec3
和 btVector3
。它们是完全相同的数据结构,但它们让我很烦,因为它们不能很好地结合在一起。必须进行大量手动转换。
假设我有一个函数 foo(btVector3 f)
,我想传递一个 glm::vec3
作为参数,而无需事先将其转换为 btVector3
,类似于传递 const char *
到需要 std::string
的函数中,而不必先将其转换为字符串。
现在我不想进入这些库中的每一个并手动将 operator
放入 类,只是为了在我更新库时破坏它(假设它是偶数他们的许可证允许)。我如何在我自己的项目中将一种类型的矢量自动转换为另一种类型的矢量,反之亦然,而无需进入内部并自行编辑库?
据我所知,您不能在 class 之外实现隐式转换运算符。我过去在类似情况下所做的只是创建几个简单的转换函数,它们的名称非常短(但仍然可以理解)。
所以在你的例子中,假设每个向量只有 3 个字段 x, y, z
,这样的函数看起来像这样
inline btVector3 glm2bt(const glm::vec3& vec)
{
return { vec.x, vec.y, vec.z };
}
inline glm::vec3 bt2glm(const btVector3& vec)
{
return { vec.x, vec.y, vec.z };
}
查看完整示例 at Coliru
然后,如果您有一个函数 foo
使用其中一种类型
void foo(glm::vec3 v) { /* implementation */ }
而且你想给它提供另一种类型的对象,调用者站点的代码仍然会很紧凑
btVector3 vec = getVectorFromSomeWhere();
foo(bt2glm(vec));
实际上,根据我在类似情况下的个人经验,回想起来,我认为这是一个比我能够定义您正在寻找的隐式转换运算符更好的解决方案。只需多输入几个符号,您就可以轻松找到这些第三方库之间的所有相互依赖关系。这在您的代码库生命周期的某个时刻可能变得非常重要。
似乎没有办法在不修改至少一个 classes 的情况下使两个 classes 隐式转换:
来自 C++ 规范
When considering the argument to a constructor or to a user-defined
conversion function, only one standard conversion sequence is allowed
(otherwise user-defined conversions could be effectively chained).
和
An expression e is said to be implicitly convertible to T2 if and only
if T2 can be copy-initialized from e, that is the declaration T2 t =
e; is well-formed (can be compiled), for some invented temporary t.
如果你看看复制初始化意味着什么
http://en.cppreference.com/w/cpp/language/copy_initialization
只能使用转换构造函数,甚至不能使用赋值运算符。由于您无法向 classes 添加构造函数,因此您将无法使用派生的 class。但是,由于无法链接隐式转换(即编译器在使用中间类型将 A 转换为 C 时不会查找转换),因此在某些情况下您至少需要显式转换。
使用派生的想法 class,但是,它可能没有您想象的那么频繁。如果您将任何中间向量变量声明为您自己的 class,则只需要在将 return 值从一个库直接传递到另一个库时显式转换。你可以做到这一点:
MyVec v = GLM::GetVector(a,b,c); // returns GLM::vec3
Bullet::TransformV(v, matrix); // accepts btVector3
你 class 会是这样的:
class MyVec : GLM::vec3
{
public:
MyVec(GLM::vec3 *vec) {
....
}
MyVec(btVector3 *vec) {
....
}
operator btVector3*() const { ... }
}
我正在使用 GLM 和 Bullet Physics,它们都有自己的矢量类型 - glm::vec3
和 btVector3
。它们是完全相同的数据结构,但它们让我很烦,因为它们不能很好地结合在一起。必须进行大量手动转换。
假设我有一个函数 foo(btVector3 f)
,我想传递一个 glm::vec3
作为参数,而无需事先将其转换为 btVector3
,类似于传递 const char *
到需要 std::string
的函数中,而不必先将其转换为字符串。
现在我不想进入这些库中的每一个并手动将 operator
放入 类,只是为了在我更新库时破坏它(假设它是偶数他们的许可证允许)。我如何在我自己的项目中将一种类型的矢量自动转换为另一种类型的矢量,反之亦然,而无需进入内部并自行编辑库?
据我所知,您不能在 class 之外实现隐式转换运算符。我过去在类似情况下所做的只是创建几个简单的转换函数,它们的名称非常短(但仍然可以理解)。
所以在你的例子中,假设每个向量只有 3 个字段 x, y, z
,这样的函数看起来像这样
inline btVector3 glm2bt(const glm::vec3& vec)
{
return { vec.x, vec.y, vec.z };
}
inline glm::vec3 bt2glm(const btVector3& vec)
{
return { vec.x, vec.y, vec.z };
}
查看完整示例 at Coliru
然后,如果您有一个函数 foo
使用其中一种类型
void foo(glm::vec3 v) { /* implementation */ }
而且你想给它提供另一种类型的对象,调用者站点的代码仍然会很紧凑
btVector3 vec = getVectorFromSomeWhere();
foo(bt2glm(vec));
实际上,根据我在类似情况下的个人经验,回想起来,我认为这是一个比我能够定义您正在寻找的隐式转换运算符更好的解决方案。只需多输入几个符号,您就可以轻松找到这些第三方库之间的所有相互依赖关系。这在您的代码库生命周期的某个时刻可能变得非常重要。
似乎没有办法在不修改至少一个 classes 的情况下使两个 classes 隐式转换:
来自 C++ 规范
When considering the argument to a constructor or to a user-defined conversion function, only one standard conversion sequence is allowed (otherwise user-defined conversions could be effectively chained).
和
An expression e is said to be implicitly convertible to T2 if and only if T2 can be copy-initialized from e, that is the declaration T2 t = e; is well-formed (can be compiled), for some invented temporary t.
如果你看看复制初始化意味着什么 http://en.cppreference.com/w/cpp/language/copy_initialization
只能使用转换构造函数,甚至不能使用赋值运算符。由于您无法向 classes 添加构造函数,因此您将无法使用派生的 class。但是,由于无法链接隐式转换(即编译器在使用中间类型将 A 转换为 C 时不会查找转换),因此在某些情况下您至少需要显式转换。
使用派生的想法 class,但是,它可能没有您想象的那么频繁。如果您将任何中间向量变量声明为您自己的 class,则只需要在将 return 值从一个库直接传递到另一个库时显式转换。你可以做到这一点:
MyVec v = GLM::GetVector(a,b,c); // returns GLM::vec3
Bullet::TransformV(v, matrix); // accepts btVector3
你 class 会是这样的:
class MyVec : GLM::vec3
{
public:
MyVec(GLM::vec3 *vec) {
....
}
MyVec(btVector3 *vec) {
....
}
operator btVector3*() const { ... }
}