使向量3D从向量ND派生,需要保留字段x y z [英] make vector 3D derived from vector ND, need to retain field x y z

查看:86
本文介绍了使向量3D从向量ND派生,需要保留字段x y z的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有矢量3D课

class Vector3D{
    public: float x; float y; float z;
    //some functions, e.g. operator+ - * / 
    //some 3D-specific function
};

和向量N-D类.

template<int constSize> class VecFloatFix{
    float database[constSize];
    //some functions, e.g. operator+ - * / 
};

我注意到两个类之间存在代码重复,所以我认为我应该将Vector3D派生自VecFloatFix<3>:-

I noticed that there is code-duplication between two classes, so I think I should make Vector3D derived from VecFloatFix<3> :-

class Vector3D : public VecFloatFix<3>{
    //some 3D-specific function
};

一切似乎都不错,只是直接有很多用户代码可以访问Vector3D::x,y,z.

Everything seems to be good, except that there are a lot of user code access Vector3D::x,y,z directly.

是否可以在不破坏用户代码的情况下从VecFloatFix<3>派生Vector3D?

Is it possible to make Vector3D derived from VecFloatFix<3> while not break user's code?

我最好的猜测是:-

template<int constSize> class VecFloatFix{
    union{
        float database[constSize];
        float x,y,z;  ?????  sound like a hack
    }
    //some functions, e.g. operator+ - * / 
};

编辑:将x,y,z硬编码为VecFloatFix是不可持续的.
如果我有一个从VecFloatFix<2>派生的新类Vector2D,则Vector2D::z可以正常编译(危险).

Hardcoding x,y,z into VecFloatFix is unsustainable.
If I have a new class Vector2D that derived from VecFloatFix<2>, Vector2D::z will compile fine (dangerous).

推荐答案

由于它使用实现定义的行为,而且可能是未定义的行为,因此不能保证该方法能正常工作.一个明智的实现将可能达到预期的效果.

This is by no ways guaranteed to work as it uses implementation-defined and possibly undefined behaviour. A sensible implementation will probably behave as expected though.

template<int constSize> 
class VecFloatFix{
public:
  union {
    float database[constSize];
    struct {
        int x, y, z;
    };
  };
};

这也使database公开.没有找到解决方法,但是没什么大不了的,因为无论如何您提供operator[].

This also leaves database public. Don't see a way around this, but no big deal since you provide operator[] anyway.

假定constSize >= 3.如果您需要较小的尺寸,则可以通过增加一些黑客来实现.所有向量都将具有x yz成员,但是只有3D及更高版本才能使用它们. 2D向量将仅具有xy可用(z的任何使用都可能导致错误),而1D向量将仅具有x.请注意,我拒绝对以下任何情况承担责任.

This assumes constSize >= 3. If you need smaller sizes, this is doable through a bit more hackery. All vectors will have x y and z members but only 3D and above will have them all usable. The 2D vector will have only x and y usable (any use of z is likely to result in an error) and the 1D vector will have just x. Note I refuse to take responsibility for any of the following.

template<int constSize>
class VecFloatFix{
    public:
        union {
            float database[constSize];
            struct {
                float x;
            };
            struct {
                spacer<constSize, 1> sp1;
                typename spacer<constSize, 1>::type y;
            };
            struct {
                spacer<constSize, 2> sp2;
                typename spacer<constSize, 2>::type z;
            };
        };
};

其中spacer的定义方式如下:

template <int N, int M, bool enable>
struct filler;

template <int N, int M>
struct filler<N, M, true>
{
    float _f[M];
    typedef float type;
};

template <int N, int M>
struct filler<N, M, false>
{
    struct nothing {};
    typedef nothing type;
};

template <int N, int M>
struct spacer
{
    filler<N, M, (N>M)> _f;
    typedef typename filler<N, M, (N>M)>::type type;
};

试驾:

VecFloatFix<4> vec4;
VecFloatFix<3> vec3;
VecFloatFix<2> vec2;
VecFloatFix<1> vec1;

`smoke test`
vec3.database[0] = 42;
vec2.database[1] = 99;
std::cout << vec3.x << std::endl;
std::cout << vec2.y << std::endl;

// make sure `y` aliases `database[1]`
std::cout << & vec2.y << std::endl;
std::cout << & vec2.database[1] << std::endl;

// make sure sizes are as expected
std::cout << sizeof(vec4) << " " << sizeof (vec3) << " " << sizeof(vec2) << " " << sizeof(vec1) << std::endl;

这篇关于使向量3D从向量ND派生,需要保留字段x y z的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆