Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ semantic type wrapping

I have a data type for example class Vector3. Now I need to create several classes with same interface as Vector3, but with higher level semantic (for example: Position, Velocity). Using typedef is not enough, because I need these types to be distinct so that they can be used for overloading. In C++0x I could probably use constructor inheritance:

struct Position: public Vector3 {
    using Vector3::Vector3;
};

Could there be any problems with this? Is there any better way to do it? Is it possible to do it without using C++0x features and not having to explicitly write all Vector3 constructors?

like image 211
Juraj Blaho Avatar asked Jun 17 '11 08:06

Juraj Blaho


Video Answer


2 Answers

Consider using a tag struct

struct tagPosition {};
struct tagDirection {};
struct tagGeneric {};

namespace detail
{
    template <typename Tag=tagGeneric>
        class Vector3
    {
        // business as usual
    };
}

typedef detail::Vector3<tagPosition>  Position;
typedef detail::Vector3<tagDirection> Direction;
typedef detail::Vector3<tagGeneric>   Vector3;

For bonus points, have conversion operators/constructors:

    template <typename Tag=tagGeneric>
        class Vector3
    {
        template <typename OtherTag>
            explicit Vector3(const Vector3<OtherTag>& rhs) { /* ... */ }

//      template <typename OtherTag>
//            operator Vector3<OtherTag>() const { return /* ... */ }
    };

If you like to live dangerously you can drop the explicit keyword, or enable the implicit conversion operator. This would have the 'benefit' of being able to enable promiscuous operator resolutions like so:

 Position pos;
 Direction dir;
 Generic gen;

 dir = gen + pos; // you see why I call it 'promiscuous'?

I'd recommend (instead) to define explicit operators for cases like this (free functions:)

 Position operator+(const Position& v, const Translation& d) { /* .... */ }

That way your class model reflects the semantics of your classes.

C++0x would possibly contain things to enable explicit conversion operators, IIRC:

In the case of converting constructors, you can disable implicit conversions by declaring the constructor as explicit The N1592 proposal stretches the semantics of this keyword to all conversion operators. A conversion operator declared explicit will not perform an implicit conversion. Instead, the programmer will have to call it explicitly

like image 63
sehe Avatar answered Sep 20 '22 11:09

sehe


When I've needed distinct-but-similar types I've generally used a dummy template parameter, like (off the cuff, untouched by compiler's dirty hands)

template< class UniqueId >
struct Blah {};

typedef Blah< struct AlphaId > Alpha;
typedef Blah< struct BetaId > Beta;

This may or may not be what you need.

Cheers & hth.,

like image 20
Cheers and hth. - Alf Avatar answered Sep 21 '22 11:09

Cheers and hth. - Alf