开发者

Using templates for 2D/3D point

开发者 https://www.devze.com 2023-01-20 05:00 出处:网络
Is it worth to write classes representing 1D, 2D, 3D points using templates t开发者_开发知识库emplate <class T>

Is it worth to write classes representing 1D, 2D, 3D points using templates

t开发者_开发知识库emplate <class T>
class Point2D
{

protected:

    T X, Y;

public:

    Point2D(const T x, const T y) : hot smileyx), Y(y)) {}
    ...
};


template <class T>
class Point3D : public Point2D<T>
{
    protected:
    T Z;

public:

    Point3D(const T x, const T y, const T z) : Point2D<T>(x,y), Z(z) {}
...
};

...or using this approach:

class Point2D
{

protected:

    double X, Y;

public:

    Point2D(const double x, const double y) : X(x), Y(y)) {}
    ...
};



class Point3D : public Point2D
{
    protected:
    double Z;

public:

   Point3D(const double x, const double y, const double z) : Point2D(x,y), Z(z) {}
...
};

We understand the coordinates as continuous variables, so it makes sense to express them using double values. A similar situation arises when working with matrices. However in this case templates are widely used...

This class is not only for single use, but it will be part of the library... And my second part of the question. How some "measure" functions should be implemented?

template <class T>
T getDist(const Point2D <T> * p1, const Point2D<T> *p2)
{
....
}

or

double  getDist(const Point2D <T> * p1, const Point2D<T> *p2)
{
....
}

Is it reasonable to write such function in general or for some specific type?


Why repeat yourself? Most of the content of those classes and functions will be the same.

Something like this works much better:

template <std::size_T N, typename T>
class Point
{
public:
    Point()
    {
        std::fill_n(mData, N, T());   
    }

    explicit Point(const T& pX) :
    mData[0](pX)
    {
        // or some variant (enable_if also works)
        static_assert(N == 1, "X constructor only usable in 1D");
    }


    explicit Point(const T& pX, const T& pY) :
    mData[0](pX),
    mData[1](pY),
    {
        static_assert(N == 2, "XY constructor only usable in 2D");
    }

    // incomplete, left as exercise for reader. :P

private:
    T mData[N];
};

And you just use loops for the functions:

template <std::size_T N, typename T>
T getDist(const Point<N, T>& pFirst, const Point<N, T>& pSecond)
{
    // generic, compiler will unroll loops
}


Based on my experience, I'd avoid like the plague creating a class hierarchy where a 3D point IS-A 2D point. It makes it far too easy for 3D points to unintentionally and silently be treated as 2D points. Better to keep coordinates of different dimensionality distinct types (as per GMan's answer) and require explicit coercion between types.

My current favourite implementation of this sort of thing is provided by Eigen. Even if it's license (LGPL) limits it's use to you, I'd suggest taking a look at it's elegantly templated vector and matrix types and learning from them.


It looks OK to me, provided that all functions are implemented correctly and efficiently. For distance measurement:

template <class T>
T getDist(const Point3D <T>& p1, const Point3D<T>& p2);

signature should be used. Distances can be in 3D also.


I've run into this situation, and had cause to allow different types for the X and Y values, where X was sometimes integral but Y always had higher precision (float or double depending on usage). Might be worth considering that upfront.


Some consideration should also be made on how the class will be used. You mentioned matrices. If you plan on solving systems using that class or anything else incolving matrix inversions (or other similar matrix operations) representing a matrix as a bunch of integers would be outlandish.

If you plan to use it as simply a table of sorts (or are only going to be adding/subtracting and multiplying the matrices) then you could template the class because a matrix full of integers would not provide weird (and incorrect) results for those operations.

0

精彩评论

暂无评论...
验证码 换一张
取 消