Поосмотрел я тут на всплывшие "минусы STL" и вспомнил ещё более древний флейм про signed vs unsigned.
И подумалось мне, что мастера выразительности и декларативности, скучающие по паскалевским отрезкам целых типов должны бы использовать что-то вроде следующего:
#ifndef IntRange_h
#define IntRange_h
#include <assert.h>
template<int TMinVal, int TMaxVal>
struct IntRange {
enum Type {
MinValue = TMinVal,
MaxValue = TMaxVal
};
static bool IsValid( int a ) { return MinValue <= a && a <= MaxValue; }
static Type To( int a ) { assert( IsValid( a ) ); return static_cast<Type>( a ); }
static Type& SetTo( Type& dst, int a2 ) { return dst = To( a2 ); }
static Type Plus( int a1, int a2 ) { return To( a1 + a2 ); }
static Type Minus( int a1, int a2 ) { return To( a1 - a2 ); }
static Type Mult( int a1, int a2 ) { return To( a1 * a2 ); }
static Type Div( int a1, int a2 ) { assert( a2 != 0 ); return To( a1 / a2 ); }
static Type Rest( int a1, int a2 ) { assert( a2 != 0 ); return To( a1 % a2 ); }
friend inline bool IsValid( Type a ) { return IntRange::IsValid( a ); }
friend inline Type MinValue( const Type& ) { return IntRange::MinValue; }
friend inline Type MaxValue( const Type& ) { return IntRange::MaxValue; }
friend inline Type& SetTo( Type& dst, int a2 ) { return IntRange::SetTo( dst, a2 ); }
friend inline bool IsMinValue( Type a ) { return a == MinValue; }
friend inline bool IsMaxValue( Type a ) { return a == MaxValue; }
friend inline Type Succ( Type a ) { return a + 1; }
friend inline Type Pred( Type a ) { return a - 1; }
friend inline Type operator + ( Type a1, Type a2 ) { return Plus( a1, a2 ); }
friend inline Type operator + ( Type a1, int a2 ) { return Plus( a1, a2 ); }
friend inline Type operator + ( int a1, Type a2 ) { return Plus( a1, a2 ); }
friend inline Type& operator += ( Type& dst, int a2 ) { return dst = dst + a2; }
friend inline Type operator - ( Type a1, Type a2 ) { return Minus( a1, a2 ); }
friend inline Type operator - ( Type a1, int a2 ) { return Minus( a1, a2 ); }
friend inline Type operator - ( int a1, Type a2 ) { return Minus( a1, a2 ); }
friend inline Type& operator -= ( Type& dst, int a2 ) { return dst = dst - a2; }
friend inline Type operator * ( Type a1, Type a2 ) { return Mult( a1, a2 ); }
friend inline Type operator * ( Type a1, int a2 ) { return Mult( a1, a2 ); }
friend inline Type operator * ( int a1, Type a2 ) { return Mult( a1, a2 ); }
friend inline Type& operator *= ( Type& dst, int a2 ) { return dst = dst * a2; }
friend inline Type operator / ( Type a1, Type a2 ) { return Div( a1, a2 ); }
friend inline Type operator / ( Type a1, int a2 ) { return Div( a1, a2 ); }
friend inline Type operator / ( int a1, Type a2 ) { return Div( a1, a2 ); }
friend inline Type& operator /= ( Type& dst, int a2 ) { return dst = dst / a2; }
friend inline Type operator % ( Type a1, Type a2 ) { return Rest( a1, a2 ); }
friend inline Type operator % ( Type a1, int a2 ) { return Rest( a1, a2 ); }
friend inline Type operator % ( int a1, Type a2 ) { return Rest( a1, a2 ); }
friend inline Type& operator %= ( Type& dst, int a2 ) { return dst = dst % a2; }
friend inline Type operator ++ ( Type& a ) { return a += 1; }
friend inline Type operator ++ ( Type& a, int ) { Type res = a; a += 1; return res; }
friend inline Type operator -- ( Type& a ) { return a -= 1; }
friend inline Type operator -- ( Type& a, int ) { Type res = a; a -= 1; return res; }
};
#endif//!IntRange_h
Ну а используется оно как-то так:
IntRange<1, 3>::Type x = MinValue( x );
x = x + 1;
x += 1;
--x;
x++; IntRange<-2, 2>::Type y = MaxValue( y );
Set( x, y );
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
E>Поосмотрел я тут на всплывшие "минусы STL" и вспомнил ещё более древний флейм про signed vs unsigned.
E>И подумалось мне, что мастера выразительности и декларативности, скучающие по паскалевским отрезкам целых типов должны бы использовать что-то вроде следующего:
Для этого есть boost::numeric_cast, если сильно хочется. И вообще, если некий тип может содержать числа только от 0 до 42 и при этом не является enum, то что-то крепко не так.
Я сейчас думаю, что unsigned — это как коммунизм: правильное решение, но общество не доросло.
Здравствуйте, Roman Odaisky, Вы писали:
RO>Для этого есть boost::numeric_cast, если сильно хочется. И вообще, если некий тип может содержать числа только от 0 до 42 и при этом не является enum, то что-то крепко не так.
Посмотри внимательнее! IntRange<0, 42>::Type -- он enum и есть!!!
А чем тут поможет boost::numeric_cast?
RO>Я сейчас думаю, что unsigned — это как коммунизм: правильное решение, но общество не доросло.
Эта тема про другое...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
RO>>Для этого есть boost::numeric_cast, если сильно хочется. И вообще, если некий тип может содержать числа только от 0 до 42 и при этом не является enum, то что-то крепко не так. E>Посмотри внимательнее! IntRange<0, 42>::Type -- он enum и есть!!! :)
E>>А чем тут поможет boost::numeric_cast?
RO>Он как раз использует std::numeric_limits<X>::{min|max}.
Погоди, как он поможет родить тип, являющийся динамически контролируемым отрезком int?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
E>Поосмотрел я тут на всплывшие "минусы STL" и вспомнил ещё более древний флейм про signed vs unsigned.
E>И подумалось мне, что мастера выразительности и декларативности, скучающие по паскалевским отрезкам целых типов должны бы использовать что-то вроде следующего:
Здравствуйте, Erop, Вы писали:
E>>>А чем тут поможет boost::numeric_cast? RO>>Он как раз использует std::numeric_limits<X>::{min|max}. E>Погоди, как он поможет родить тип, являющийся динамически контролируемым отрезком int?
Можно сделать тип, специализировать им std::numeric_limits, и на каждый чих вызывать boost::numeric_cast.
Здравствуйте, Roman Odaisky, Вы писали:
RO>Можно сделать тип, специализировать им std::numeric_limits, и на каждый чих вызывать boost::numeric_cast.
Не, это не кузёво.
Всё-таки IntRange<5, 18> будет работать сам. Автоматически...
Кстати, а что ты ожидаешь от выражения color + 8?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Это не прикольно, вернее это не то.
IntRange<8, 12>::Type -- это настоящий enum, то есть стандартный тип. Его, например, все компиляторы будут передавать через регистры, будут всякие fastcall работать, отладчики показывать и всё такое
Его преобразование в int будет не пользовательским, его можно хранить в bitfields и т. д.
Скажем можно написать так:
Всё честно. Никаких указателей, никаких объектов, чистый честный c++ enum...
Если таки требование выражать требования к диапазону допустимых значений так насущно необходимо, как участники той дискуссии утвеждали (а я не думаю, что они писали не то, что думают), то, IMHO, очень в тему конструкиця, таки...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Roman Odaisky, Вы писали:
RO>>>И вообще, если некий тип может содержать числа только от 0 до 42 и при этом не является enum, то что-то крепко не так. E>>Посмотри внимательнее! IntRange<0, 42>::Type -- он enum и есть!!!
RO>
Во-первых, таки это обозначает, что ты считаешь, что отрезки целого ряда не нужны.
Хотя вполне может быть что-то типа числа месяца, которое должно быть от 1 до 31...
Или, скажем, такой тип, как "число процентов", которое от 0 до 100...
Во-вторых, если ты считаешь, что нормально, что White + 1 == Yellow, то можно сделать как-то так:
BEGIN_ENUM_WITH_MATH( RGB )
Red, Green, Blue
END_ENUM_WITH_MATH( Red, Blue )
void iterateColours()
{
const RGB::Type prohColor = RGD::Green; // Объект скорее всего не заведётся, так как RGB::Type -- честный enum!!!for( RGB::Type color = MinValue( color ); ; color++ ) {
if( color != prohColor )
processColor( color );
if( IsMaxValue( color ) )
break;
}
}
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, igna, Вы писали:
I>Можно перенести проверку и на этап компиляции. Вот набросок:
I> d = a + b; // error: no operator "=" matches these operands
I> // operand types are: ranged_int<0, 10> = ranged_int<0, 20>
I>}
I>
А в чём идея проверять на этапе компиляции rt-условия?
проще уж тогда просто константное выражение посчитать...
Кроме того, твой ranged_int -- это объект класса, а IntRange<1, 8>::Type -- это честный enum, стандартный тип, то, сё...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском