Комментарии 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;
вы рискуете встать на грабли.
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;
вы рискуете встать на грабли.
typedef по истине своей великолепны в метапрограммировании, когда они выступают в роли свойств типов (traits)
Думаю, полезно будет упомянуть, что такой подход имеет свое название:
Шаблон проектирование Money (Деньги)
Шаблон проектирование Money (Деньги)
Разве это он? По-моему, Money больше похож на тип Any (или dynamic в C#), так как призван унифицировать использование различных типов, а в сатье, наоборот, из одного типа делается несколько де факто различных.
Основная цель шаблона деньги — исключить ошибки, возникающие при присвоении различных значений друг другу.
Деньги, к примеру, могут быть реализованы с использованием приведенного в статье шаблонного класса. Тогда разные валюты нельзя будет перепутать и присваивать без явной конвертации. Это даже лучше, т.к. покупка/продажа валют имеют разный курс и лишние конвертации никому не нужны. Также определенные операции могут быть доступны только в какой-то определенной валюте.
А унификацию и это Вы уже сами придумали.
Деньги, к примеру, могут быть реализованы с использованием приведенного в статье шаблонного класса. Тогда разные валюты нельзя будет перепутать и присваивать без явной конвертации. Это даже лучше, т.к. покупка/продажа валют имеют разный курс и лишние конвертации никому не нужны. Также определенные операции могут быть доступны только в какой-то определенной валюте.
А унификацию и это Вы уже сами придумали.
Можно это дело ещё обернуть в макрос с автоподставлением уникального TAG_##CLASSNAME и нужным typedef-ом.
Кстати, по поводу последнего абзаца можно попробовать добавить
В базовых ситуациях типа арифметических операций он должен выручить.
Кстати, по поводу последнего абзаца можно попробовать добавить
template < typename T >
operator T() const;
В базовых ситуациях типа арифметических операций он должен выручить.
Все хорошо, только одна ошибка — typedef таки может создавать реальные типы, я правда понятия не имею зачем, но иногда пишут так.
typedef struct
{
} SomeStruct;
Такой финт ушами создает полноценный тип, RTTI подвержает.
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
<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
Для меня это — говнокод, нужен новый тип — не ленись и не выдумывай ничего…
а если нужен просто синоним тогда typedef
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;
}
Зарегистрируйтесь на Хабре, чтобы оставить комментарий
Заставляем компилятор отличать коров от галош