2015-12-14 14:01 GMT+01:00 Rob Stewart
On December 14, 2015 3:43:25 AM EST, Andrzej Krzemienski < akrzemi1@gmail.com> wrote:
2015-12-12 1:18 GMT+01:00 Robert Ramey
: In the context of this library the safe_range ... are important for a very special reason. The bounds are carried around with type of expression results. So if I write
save<int> a, x, b, y; y = a * x + b;
runtime checking will generally have to be performed. But if I happen to know that my variables are limited to certain range.
safe_integer_range<-100, 100> a, x, b, y; y = a * x + b;
Then it can be known at compile time that y can never overflow so no runtime checking is required. Here we've achieved the holy grail:
a) guaranteed correct arithmetic result b) no runtime overhead. c) no exception code emitted. d) no special code - we just write algebraic expressions
This is the true motivation for safe_..._range
Why isn't that the behavior of your safe type in the first place? That is, what benefit does your safe type offer that it shouldn't just be supplanted by the range type?
Ok, now I think I understand the scope of the library. You give me the tool for representing a mathematical notion of an integral number within *some* limited range. The contract is:
You guarantee: 1. Either correct result or a compile time error or a run-time exception. 2. No memory management: you will only take the space of one scalar type.
I specify the range of the representable values. I can say: 1. "From -100 to +100", or 2. "Whatever range 'int' as on my machine".
But if I got it right, I would say that the choice of the name, and the interface do not indicate the intent as clear as they could. Imagine the following alternative interface:
small_int
>; // range-based policy small_int ; // underlying-type-based policy In the first case, the user specifies the range, and the library can choose the best underlying type for the job.
In the second case, the user chooses the underlying type, and this implies the range [numeric_limits<T>::min(), numeric_limits<T>::max()]
That seems like a reasonable idea, but what about the latter is "small" and not "safe" that you think the name should be "small_int"?
You have "big_integer" (or "integer") to represent a mathematical notion of integer that allocates memory. Analogously, you would have "small_integer" that represents a mathematical notion of integer with a reduced range of values. "safe_int" does not convey the idea of a higher level abstraction: it sounds like "an ordinary low-level 'int' with some modified rules".
Once you need two types to distinguish between a user-defined range, and a numeric_limits-defined range, why not just use two template names, like safe_range and safe_int? That would eliminate your p_range and p_type policies.
However, since min() and max() are now constexpr, that all can be collapsed into a single template with three parameterizing types: the underlying type, the minimum, and the maximum:
template < class T , T Min = std::numeric_limits<T>::min() , T Max = std::numeric_limits<T>::max()
class safe;
Current implementation has more of these policies (e.g., for how you want to report overflow). Regards, &rzej