Как стать автором
Обновить

Комментарии 17

Определив в одном файле
typedef strong_type<unsigned int, class TAG_not_unique_t> a_count_t;

а в другом
typedef strong_type<unsigned int, class TAG_not_unique_t> b_count_t;

вы рискуете встать на грабли.
Это решается конвенцией, что тэг должен быть таким же, как и определяемый тип, только с прификсом TAG. Ну или любой другой, как вам нравится. Это легко отлавливается во время ревизии кода.
Нужно как можно больше спихнуть на компилятор или препроцессор.

#define SUPER_TYPEDEF(OrigType, NewType) \
typedef strong_type<OrigType, class TAG##NewType> NewType;
Можно и так, я просто не очень люблю макросы и стараюсь их избегать. Врочем, это дело вкуса.
typedef по истине своей великолепны в метапрограммировании, когда они выступают в роли свойств типов (traits)
Разве это он? По-моему, Money больше похож на тип Any (или dynamic в C#), так как призван унифицировать использование различных типов, а в сатье, наоборот, из одного типа делается несколько де факто различных.
Основная цель шаблона деньги — исключить ошибки, возникающие при присвоении различных значений друг другу.

Деньги, к примеру, могут быть реализованы с использованием приведенного в статье шаблонного класса. Тогда разные валюты нельзя будет перепутать и присваивать без явной конвертации. Это даже лучше, т.к. покупка/продажа валют имеют разный курс и лишние конвертации никому не нужны. Также определенные операции могут быть доступны только в какой-то определенной валюте.

А унификацию и это Вы уже сами придумали.
Можно это дело ещё обернуть в макрос с автоподставлением уникального TAG_##CLASSNAME и нужным typedef-ом.
Кстати, по поводу последнего абзаца можно попробовать добавить
template < typename T >
operator T() const;

В базовых ситуациях типа арифметических операций он должен выручить.
Все хорошо, только одна ошибка — typedef таки может создавать реальные типы, я правда понятия не имею зачем, но иногда пишут так.

typedef struct
{

} SomeStruct;

Такой финт ушами создает полноценный тип, RTTI подвержает.
Когда-то давно в классическом С, чтобы объявить переменную структуры, нужно было писать так

<code=cpp>
struct SomeStruct
{
int _s;
};

//…

struct SomeStruct s;


чтобы избежать этого делали тайпдеф

<code=cpp>
struct TAG_SomeStruct
{
int _s;
};

typdef TAG_SomeStruct SomeStruct

//…

SomeStruct s;


а так как С поддержиает анонимные структуры, то запись сократили до

<code=cpp>
typedef struct
{

} SomeStruct;

Многие по привычке до сих пор так пишут, хоть надобности в этом больше нет

А насчет новых типов если написать так
<code=cpp>
typedef struct
{

} SomeStruct, SomeOtherStruct;

То получим два псевонима, проверьте по RTTY
Для меня это — говнокод, нужен новый тип — не ленись и не выдумывай ничего…
struct galosh_count_t { size_t value; };
а если нужен просто синоним тогда typedef
Полностью согласен. Если нужно строгое разделение по типам, не поленитесь создать новый тип с удобным интерфейсом. Иначе потонете в море неявных приведений. Шаблоны всё-таки не для этого придумывали, здесь утиной типизацией даже и не пахнет. Изначально есть какой-то примитивный тип и необходимо сделать ещё два совместимых. Так и задайте два новых типа явно.
Подобная конструкция помогает при рефакторинге, когда уже есть сотни две объявленных переменных типа int и хочется заменить это все на десятка два классов. При этом нужно чтобы новые типы вели себя так-же как int, т.к. уже есть много кода, который использует переменные.
В таком случае шаблонный класс помогает избежать дублирования кода.

Как в этом случае быть с вашими структурами?
Сложно правильно выбирать решение в таких условиях. Это как, что лучше: сто строк простого С или десяток строк мудреного С++? Для облегчения входа в проект студентов, лучше делать проще, а если на проекте все гуру С++, можно и шаблоны. Мой личный опыт программирования подсказывает, что тут скорее всего надо завязываться на boost, как ниже написали
Когда-то давно я делал подобное, только заточенное на манипуляции с физическими величинами (масса, время, расстояние, сила тока и т.д.). Поддерживались различные системы измерений (СИ, СГС и т.д.) и автоматическое конвертирование между ними. На раннюю версию (но уже вполне функциональную) можно посмотреть здесь.
В boost уже есть реализация — strong typedef.

#include <iostream>
#include <boost/strong_typedef.hpp>

BOOST_STRONG_TYPEDEF(int, galosh_count_t);
BOOST_STRONG_TYPEDEF(int, cow_count_t);

void print (galosh_count_t count)
{
     std::cout << "У меня есть " << count << " пар галош!" << std::endl;
}

void print (cow_count_t count)
{
     std::cout << "У меня есть " << count << " коров!" << std::endl;
}

void print (galosh_count_t galosh_count, cow_count_t cow_count)
{
    std::cout << "У меня есть " << galosh_count << " пар галош и " << cow_count << " коров!" << std::endl;
}

int main (int, char*[])
{
    galosh_count_t galosh_count(10);
    cow_count_t cow_count(15);    

    print (galosh_count, cow_count); 
    // print (cow_count, galosh_count); // здесь будет ошибка компиляции

    print (galosh_count);
    print (cow_count);
    return 0;
}

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории