开发者

Is it necessary to specialize whole class, when differs just with few members?

I am designing class, which is almost the same for 2d and 3d, so I am trying to use templates, to create it as one class typed by vector type (2d od 3d)

Some methods and member are very same for 2d and 3d

Some (but very few) methods are slightly different, I use trait here - see doSomething()

Some members and method are present for 3d but are not for 2d (up vector) and THAT IS MY PROBLEM.

I can solve it by complete class specialization, but is there any other way, how to include/exclude these members without specialization whole class?

I have trait:

template<typename T>
struct VectorInfo{};

template<>
struct VectorInfo<Vec2>
{
    enum { dim = 2 };
};

template<>
struct VectorInfo<Vec3>
{
    enum { dim = 3 };
};

template<int Val>
struct VectorDimension
{
    enum { val = Val };
};

and Class:

template <typename vector_type>
class LocalSpace
{
public:
    ////////////////////////////////////////
    //Common for 2D and 3D
    const vector_type & getSideVector() const;      
    void setSideVector(const vector_type & s);

    const vector_type & getForwardVector() const;
    void setForwardVector(const vector_type & f);

    const vector_type & getPosition() const;
    void setPosition(const vector_type & p);

    bool isRightHanded() const;

    //others methods...

    //////////////////////////////////////////
    //only for 3D
    const vector_type & getUpVector() const;    
    void setUpVector(const vector_type & u);   

    //One of few methods differing for 2D and 3D 
    inline void doSomething(const vector_type & v)      
    {
        doSomethingImpl(v, VectorDimension<VectorInfo<vector_type>::di开发者_Go百科m>);
    }

protected:

    void doSomethingImpl(const vector_type & v, VectorDimension<2>)
    {
    }

    void doSomethingImpl(const vector_type & v, VectorDimension<3>)
    {
    }

private:
    vector_type m_side;     //2d+3d        
    vector_type m_forward;  //2d+3d
    vector_type m_up;       //3d ONLY

    vector_type m_position; //2d+3d
};

Hope you understand my question.

EDIT: thank you for your responses, now I have

struct BlankType{};

template <typename vector_type>
class LocapSpace3DBase
{
public:
    const vector_type & getUpVector() const;
    void setUpVector(const vector_type & u);
private:
    vector_type m_up;
};

template <typename vector_type>
class LocalSpace : public boost::mpl::if_c<
                                                            VectorInfo<vector_type>::dim == 3,
                                                            LocapSpace3DBase<vector_type>,
                                                            BlankType>::type

Is there any way, to get rid of the BlankType? Like - if the dimension is 3, derive from 3DBase, if not, DO NOTHING (instead of derive from empty struct)?


You can derive from different base classes using mpl::if_ or mpl::if_c. In the branch for 3d you can declare the members and methods needed only for 3d case.

Something like this:

class LocalSpaceBase2
{
    vector_type m_up;
    // ...
};

template <typename vectortype>
class LocalSpace : public boost::mpl::if_c<
                              boost::is_same<vectortype, Vec3>,
                              LocalSpaceBase3,
                              LocalSpaceBase2>::type
{
    ...


boost::enable_if<> is designed just for cases like this.


Yes: if you specialize the template, you have to specialize the whole template.

However, there is an easier solution: just put all of the members, even the 3-D specific ones, into the primary template and then add static_asserts to the 3-D specific members to ensure they are only used for a 3-D vector.

This isn't a particularly scalable solution, but if you only have one or two specializations, it's straightforward and it is simple to refactor later if you need more flexibility.

0

上一篇:

下一篇:

精彩评论

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

最新问答

问答排行榜