Как проще всего организовать два неприводимых неявно друг к другу целочисленных типа.
То есть, хочется чтобы компилятор автоматически отслеживал ошибки наподобие:
// <какое-то объявление неприводимых друг к другу целочисленных типов type_1, type_2>void f(type_1 _x)
{
//<bla-bla>
}
void main()
{
type_1 x;
type_2 u;
x = u; //должен выдать ошибку
f(u); //должен выдать ошибку
};
Спасибо.
Re: Как организовать неприводимые друг к другу целочисленные типы?
Здравствуйте, _hum_, Вы писали:
__>Как проще всего организовать два неприводимых неявно друг к другу целочисленных типа. __>То есть, хочется чтобы компилятор автоматически отслеживал ошибки наподобие:
Re[2]: Как организовать неприводимые друг к другу целочисленные типы?
Здравствуйте, swingus, Вы писали:
S>BOOST_STRONG_TYPEDEF()
S>Здравствуйте, _hum_, Вы писали:
__>>Как проще всего организовать два неприводимых неявно друг к другу целочисленных типа. __>>То есть, хочется чтобы компилятор автоматически отслеживал ошибки наподобие:
а без буста никак? во-первых, не хочется сторонние библиотеки,а во-вторых, хочется простоты и прозрачности кода.
Re: Как организовать неприводимые друг к другу целочисленные типы?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re: Как организовать неприводимые друг к другу целочисленные типы?
Здравствуйте, _hum_, Вы писали:
S>>BOOST_STRONG_TYPEDEF()
__>а без буста никак? во-первых, не хочется сторонние библиотеки,а во-вторых, хочется простоты и прозрачности кода.
Ну скопируй конкретно это из буста, оно маленькое, особенно если тебе не нужно кучу разных компиляторов поддерживать.
Здравствуйте, Erop, Вы писали:
E>Здравствуйте, _hum_, Вы писали:
__>>Как проще всего организовать два неприводимых неявно друг к другу целочисленных типа. E>оно
Не совсем понимаю вашу идею использования литералов для моей проблемы. Можете пояснить?
Здравствуйте, jazzer, Вы писали:
J>Здравствуйте, _hum_, Вы писали:
S>>>BOOST_STRONG_TYPEDEF()
__>>а без буста никак? во-первых, не хочется сторонние библиотеки,а во-вторых, хочется простоты и прозрачности кода.
J>Ну скопируй конкретно это из буста, оно маленькое, особенно если тебе не нужно кучу разных компиляторов поддерживать.
Во-первых, оно не маленькое, ибо ссылается и на другие бустовские вещи типа boost::totally_ordered1,
#include <boost/config.hpp>
#include <boost/operators.hpp>
#if !defined(__BORLANDC__) || __BORLANDC__ >= 0x590
#define BOOST_STRONG_TYPEDEF(T, D) \
struct D \
: boost::totally_ordered1< D \
, boost::totally_ordered2< D, T \
> > \
{ \
T t; \
explicit D(const T t_) : t(t_) {}; \
D(){}; \
D(const D & t_) : t(t_.t){} \
D & operator=(const D & rhs) { t = rhs.t; return *this;} \
D & operator=(const T & rhs) { t = rhs; return *this;} \
operator const T & () const {return t; } \
operator T & () { return t; } \
bool operator==(const D & rhs) const { return t == rhs.t; } \
bool operator<(const D & rhs) const { return t < rhs.t; } \
};
#else
#define BOOST_STRONG_TYPEDEF(T, D) \
struct D \
: boost::totally_ordered1< D \
, boost::totally_ordered2< D, T \
> > \
{ \
T t; \
explicit D(const T t_) : t(t_) {}; \
D(){}; \
D(const D & t_) : t(t_.t){} \
D & operator=(const D & rhs) { t = rhs.t; return *this;} \
D & operator=(const T & rhs) { t = rhs; return *this;} \
/*operator const T & () const {return t; }*/ \
operator T & () { return t; } \
bool operator==(const D & rhs) const { return t == rhs.t; } \
bool operator<(const D & rhs) const { return t < rhs.t; } \
};
#endif// !defined(__BORLANDC) || __BORLANDC__ >= 0x590#endif// BOOST_STRONG_TYPEDEF_HPP
во-вторых, выглядит страшнова-то, а мне важно все контролировать, ибо от кода зависит безопасность жизни людей, ну и в-третьих, мне важна скорость выполнения кода.
По идее, должно быть что-то наподобие
template<typename IntegerType, int uid>
class strong_redefined
{
static const int s_uid;
IntegerType m_val;
public:
strong_redefined(IntegerType val = 0):m_val(val){}
explicit strong_redefined(const strong_redefined& X):m_val(X.m_val){}
strong_redefined& operator=(const strong_redefined& X){if(this != &X){m_val = X.m_val;}; return *this;}
operator IntegerType()const{return m_val;}
strong_redefined& operator+(IntegerType i){m_val += i; return *this;}
//....
//<остальные операторы для типа IntegerType >
//....
};
template<typename IntegerType, int uid>
int strong_redefined<IntegerType, uid>::s_uid = uid;
int _tmain(int argc, _TCHAR* argv[])
{
typedef strong_redefined<int,1> type_1;
typedef strong_redefined<int,2> type_2;
type_1 x = 10;
type_2 u = 20;
type_1 y = 15;
x = u;// ошибка компиляции
x = y;// окreturn 0;
}
Но, блин, надо тогда переопределять все операции (
Странно, почему в новом стандарте сделали строгие enum-ы, а строгих определений хотя бы для базовых типов — обошли стороной...
Re[4]: Как организовать неприводимые друг к другу целочисленные типы?
В ассемблерном коде все это все равно будет пожато до операций со встроенным int — никаких там конструкторов, деструкторов и прочей мутотени.
Осталось всего лишь: определить для intfoo|intbar operator+, operator++, operator-, operator--, ... Плюс понять, а как проводить неявное приведение int к intfoo|intbar и обратно (вы-таки будете смеяться, но не получится определить, например, operator int(intfoo) или operator intfoo(int)).
Люди! Люди, смотрите, я сошел с ума! Люди! Возлюбите друг друга! (вы чувствуете, какой бред?)
Re[2]: Как организовать неприводимые друг к другу целочисленные типы?
Здравствуйте, slava_phirsov, Вы писали:
_>Здравствуйте, _hum_, Вы писали:
__>>Как проще всего организовать два неприводимых неявно друг к другу целочисленных типа.
_>Если не хочется бюста и overhead-а на классы, то даю вредный совет:
_>
_>В ассемблерном коде все это все равно будет пожато до операций со встроенным int — никаких там конструкторов, деструкторов и прочей мутотени.
_>Осталось всего лишь: определить для intfoo|intbar operator+, operator++, operator-, operator--, ... Плюс понять, а как проводить неявное приведение int к intfoo|intbar и обратно (вы-таки будете смеяться, но не получится определить, например, operator int(intfoo) или operator intfoo(int)).
Брр.. Может, я чего-то не знаю, но объявленные вами типы содержать только два значения (а не отрезки значений от Foo0 до FooMax и от Bar0 до BarMax).
Re[3]: Как организовать неприводимые друг к другу целочисленные типы?
Здравствуйте, _hum_, Вы писали:
__>Брр.. Может, я чего-то не знаю, но объявленные вами типы содержать только два значения (а не отрезки значений от Foo0 до FooMax и от Bar0 до BarMax).
По стандарту любое целочисленное значение в диапазоне от минимального до максимального значений членов перечисления может быть приведено к типу перечисления и обратно без искажения, не?
Люди! Люди, смотрите, я сошел с ума! Люди! Возлюбите друг друга! (вы чувствуете, какой бред?)
Re[4]: Как организовать неприводимые друг к другу целочисленные типы?
Здравствуйте, slava_phirsov, Вы писали:
_>Здравствуйте, _hum_, Вы писали:
__>>Брр.. Может, я чего-то не знаю, но объявленные вами типы содержать только два значения (а не отрезки значений от Foo0 до FooMax и от Bar0 до BarMax).
_>По стандарту любое целочисленное значение в диапазоне от минимального до максимального значений членов перечисления может быть приведено к типу перечисления и обратно без искажения, не?
enum intfoo {Foo0 = 0, FooMax = 65535};
intfoo x = (intfoo)(100);//некорректно, хоть и компилируется
Re[5]: Как организовать неприводимые друг к другу целочисленные типы?
template<int TMinVal, int TMaxVal, typename Tag = void>
struct IntRange {//... дальше всё так же
Тогда
struct tag1 : IntRange<INT_MIN, INT_MAX, tag1>{ };
struct tag2 : IntRange<INT_MIN, INT_MAX, tag2>{ };
auto x = tag1::To( 10 );
auto y = tah2::To( 20 );
// x и y -- разные целые...
}
__>По идее, должно быть что-то наподобие
//...
__>Но, блин, надо тогда переопределять все операции (
Я, собственно, показал тебе как переопределять автоматом + это будет честный встроенный интегральный тип, а не класс...
+ ещё можно любой диапазон значений назначить
Тут так движок форума устроен, что лучше отвечать а каждое сообщение отдельно.
Во-первых, дерево
Во-вторых, тот, кому ответишь, может получить уведомление и ответить тебе дальше.
Я случайно заметил, что ты прочитал мой совет, например
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[5]: Как организовать неприводимые друг к другу целочисленные типы?
Здравствуйте, slava_phirsov, Вы писали:
__>>intfoo x = (intfoo)(100);//некорректно, хоть и компилируется
Ненамногим сложнее:
class IntegralFoo
{
// ... блекджек с ООП
};
IntegralFoo foo = *(IntegralFoo*)(100); // не было слышно ни вскрика, ни стона ...
Что еще раз доказывает: помешать программисту проращивать сквозь себя бамбук C++ не в состоянии — он не для того задумывался. "Хотите персональные ремни безопасности — используйте Ada" (c) Скотт Майерс
Люди! Люди, смотрите, я сошел с ума! Люди! Возлюбите друг друга! (вы чувствуете, какой бред?)
Re[5]: Как организовать неприводимые друг к другу целочисленные типы?
Здравствуйте, _hum_, Вы писали:
__>enum intfoo {Foo0 = 0, FooMax = 65535};
__>intfoo x = (intfoo)(100);//некорректно, хоть и компилируется
А почему некорректно? Стандарт же гарантирует, что лежаший под перечислением интегральный тип вмещает весь диапазон?
Только лучше static_cast использовать.
Вообще, объявляя перечисление в С++ ты же объявляешь литералы, а не значения. Значения -- числа, только типизированные.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re: Как организовать неприводимые друг к другу целочисленные типы?
И еще Страуструп как-то на одной конференции по С++ говорил про работу с константами, имеющими размерности. Что-то типа
const mass_t a = 1kg;
assert(1000g == a); // без ошибокconst distance_t b = 1cm;
std::cout << a + b; // ошибка компиляции
Думаю нормальным плюсовым подходом будет работа с разными типами, т.к. если воздействовать на существующие целочисленные типы какими-то операторами, то это может негативно сказаться на уже работающем коде.