递归类型转换
Posted
技术标签:
【中文标题】递归类型转换【英文标题】:Recursive type casting 【发布时间】:2009-06-01 05:42:46 【问题描述】:我得到了一个典型的“vector4”类,它带有一个操作符 float* 来为 gl*4fv 和 [] 自动转换它。 还有用于编译器优化的“const”版本以及 const 引用,这很好用:
typedef struct vec4
...
// ----------------------------------------------------------------- //
// Cast operator, for []
inline operator float* ()
return (float*)this;
// Const cast operator, for const []
inline operator const float* () const
return (const float*)this;
// ----------------------------------------------------------------- //
...
// Vertex / Vector
struct
float x, y, z, w;
;
// Color
struct
float r, g, b, a;
;
vec4;
我的问题是当我现在编写一个“matrix4”类时,使用支持的运算符 vec4* 从矩阵中提取行,并且还具有矩阵[][] 运算符的“副作用”,这很好。
typedef struct mat4
...
// ----------------------------------------------------------------- //
// Cast operator, for []
inline operator vec4* ()
return (vec4*)this;
// Const cast operator, for const []
inline operator const vec4* () const
return (const vec4*)this;
// ----------------------------------------------------------------- //
private:
float f[16];
mat4;
我的问题是,为什么编译器没有检测到转换 mat4 浮动*?我怀疑 mat4 -> vec4 -> float* 的继承是合理的,但似乎并非如此。 我想到编译器可能会将其视为未定义的 mat4 -> vec4* -> float*, 但是这个假设是无效的,因为定义了操作符
inline operator const vec4 () const
return (vec4)*this;
不起作用,并调用 glMultMatrixf(mat4(...)); (例如)产生与没有运算符时相同的错误消息。
在 mat4 中定义操作符 float* 当然是不可能的,因为这将消除使用 [][] 的能力(二义性操作符)
对此有任何解决方案吗?还是每次我想自动转换为浮动*时都必须手动转换为 vec4?自动投射是一个非常好的功能,它可以巧妙地使用 OpenGL 插入代码。
【问题讨论】:
inline
在类/结构声明中不需要关键字。
如果有一种方法可以为您的问题进行自动转换,那么 [][] 就已经存在一个模棱两可的运算符问题,就像您在 mat4 中定义了运算符 float* 一样。
GCC 4.3.x 似乎没有问题,它使用 operator[] 作为 [][] 和 operator const float* 作为 const float* 接受功能。 MSVC 是问题所在,所以我正在寻找另一种解决方法。
【参考方案1】:
C++ 可以执行自动转换,但按照标准不会执行两次连续的自动转换。
它被认为太有利于无意中的错误和歧义。
三个可能对您有用的选项:
当您需要矩阵中的float*
时,自己显式执行第一次转换。
FuncThatWantsFloatPointer( *static_cast<Vec4*>(MyMatrix) );
在您的矩阵类中实现到float*
的直接转换。
typedef struct mat4
...
operator const float* () const
return *static_cast<Vec4*>(*this);
mat4;
如果您喜欢使用方括号表示法,请在矩阵和向量类中实现 operator[]
typedef struct mat4
...
const vec4& operator[] ( size_t index ) const
return static_cast<Vec4*>(*this)[index];
mat4;
【讨论】:
您可以将第一个转换设为显式,这样只有一个转换是隐式的。 ((Vec4)MyMatrix) 可以转换为float* 您还可以在矩阵类中添加一个运算符,通过先将其转换为 Vec4* 将其直接转换为 float*。 @Shmoopty,这两种方法都行不通。 'explicit' 关键字仅适用于构造函数,添加 float* 将不允许我使用假运算符 [][] (mat[]vec[]float)。 我指的不是关键字。我只是在我的回答中澄清了。希望对您有所帮助。【参考方案2】:... 其中一个规则是不允许任何转换序列包含多个用户定义的转换(即,对单个争论构造函数或隐式类型转换运算符的调用)。 - 更有效的 C++,Scott Meyers
您可能希望为 vec4 和 mat4 重载 operator[]。
struct vec4
float& operator[](int index) return f[index];
const float& operator[](int index) const return f[index];
operator float*() return f;
operator const float*() const return f;
float f[4];
;
struct mat4
vec4& operator[](int row) return v[row];
const vec4& operator[](int row) const return v[row];
operator float*() return f;
operator const float*() const return f;
union
vec4 v[4];
float f[16];
;
;
int main(void)
mat4 m;
::memset(&m, 0, sizeof(mat4));
m[0][1] = 1;
cout << m[0][1] << endl; // it prints 1.
return 0;
【讨论】:
这将削弱结构 - 根本没有 '[const] float*' 转换,这对于类似 gl*4fv 的函数来说会很好。我尝试重载运算符,这对 GCC 工作正常,但 MSVC 错误和错误。虽然我并不真正关心 MSVC,但我仍然支持可移植代码。 我只是想展示如何重载 operator[]。您可以轻松添加这些操作的 const 版本。我用 MSVC 2008 测试了代码,结果很好。不过,不确定 GCC。 运算符 const float*() const return f; // 像这样。 :) 这将消除双 [][]。 (你的 = mat[15],我想要 = mat[3][3]); 嗯,我不明白你的意思。你仍然可以这样做 m[0][1] = 1;这已经在 main() 函数中。以上是关于递归类型转换的主要内容,如果未能解决你的问题,请参考以下文章