Обёртывание семантического типа в C ++ - PullRequest
6 голосов
/ 17 июня 2011

У меня есть тип данных, например class Vector3. Теперь мне нужно создать несколько классов с тем же интерфейсом, что и Vector3, но с семантикой более высокого уровня (например: Position, Velocity). Использование typedef недостаточно, потому что мне нужно, чтобы эти типы были различны, чтобы их можно было использовать для перегрузки. В C ++ 0x я мог бы использовать наследование конструктора:

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

Могут ли быть проблемы с этим? Есть ли лучший способ сделать это? Можно ли сделать это без использования функций C ++ 0x и без необходимости явно писать все конструкторы Vector3?

Ответы [ 2 ]

5 голосов
/ 17 июня 2011

Подумайте об использовании тега 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;

Для бонусных баллов есть операторы / конструкторы преобразования:

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

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

Если вы хотите жить опасно, вы можете опустить ключевое слово explicitили включите оператор неявного преобразования.Это даст «преимущество» в том, что вы сможете включить разнородные разрешения операторов, например, так:

 Position pos;
 Direction dir;
 Generic gen;

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

Я бы порекомендовал (вместо) определить явные операторыдля подобных случаев (free functions:)

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

Таким образом, ваша модель класса отражает семантику ваших классов.

C ++ 0x, возможно, будет содержать вещи для включения явногооператоры преобразования , IIRC:

В случае преобразования конструкторов вы можете отключить неявное преобразование, объявив конструктор явным. Предложение N1592 расширяет семантику этого ключевого слова.для всех операторов преобразования.Оператор преобразования, объявленный явным, не будет выполнять неявное преобразование.Вместо этого программист должен будет вызвать его явно

4 голосов
/ 17 июня 2011

Когда мне нужны разные, но похожие типы, я обычно использую фиктивный параметр шаблона, например (без манжеты, не тронут грязными руками компилятора)

template< class UniqueId >
struct Blah {};

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

Это может или не можетбудь тем, что тебе нужно.

Приветствия & hth.,

...