
Hi group, Some time ago I've written a set of class templates for bounded types (types whose variables may hold a value only from within a specified range). You can download the sources at http://www.rk.w.pl/progz/bounded. I've created a thread in comp.lang.c++.moderated (http://groups-beta.google.com/group/comp.lang.c++.moderated/browse_frm/thre ad/0298fc4ac6c6d223/) as I was hoping to work the project on and maybe transform it into a proposal for the C++0x standard library, but unfortunately the feedback was very low. Just today I saw in this newsgroup a thread titled "Checked Integral Class" concerning a very similar facility so I'm writing this post to call attention to my implementation. Maybe it would be better to include such class templates in Boost first, and then think about making a proposal for the C++ standard... Unfortuantely there's no documentation yet as this is only a sketch for further refinements, but comments in the code and posts in comp.lang.c++.moderated may answer some of your questions about design decisions and usage. If not then please ask them here or on comp.lang.c++.moderated. Any comments and suggestions are welcome. I hope there are more people who need such a facility and would like to work on it, let's finally do it - C++ lacks bounded types and it's high time to fix that! ;-) Best regards, Robert Kawulak -=##############=- <gg> 6934572 </gg> <gsm> 603654215 </gsm> <www> www.rk.w.pl </www> -=##############=- "I know not with what weapons World War III will be fought, but World War IV will be fought with sticks and stones." - Albert Einstein

let's finally do it - C++ lacks bounded types and it's high time to fix that! ;-)
I agree. I had been programming in C++ for a number of years before I was introduced to Ada. I loved the strict typing one can do in Ada and I would like to have at least some of these facilities in C++ as well (since that is what I use every day). I will certainly check out what you've posted (bounded types). One thing to keep in mind as we move forward with this is that, IMO, we need to support as much compile-time computation as much as possible. One thing I am struggling with is how to support both bounded floating-point types, but as the same time, have a bounded types template be able to be used from boost::mpl for compile-time computation. Regards, Dan McLeran

Dan McLeran wrote:
let's finally do it - C++ lacks bounded types and it's high time to fix that! ;-)
I agree. I had been programming in C++ for a number of years before I was introduced to Ada. I loved the strict typing one can do in Ada and I would like to have at least some of these facilities in C++ as well (since that is what I use every day). I will certainly check out what you've posted (bounded types). One thing to keep in mind as we move forward with this is that, IMO, we need to support as much compile-time computation as much as possible. One thing I am struggling with is how to support both bounded floating-point types, but as the same time, have a bounded types template be able to be used from boost::mpl for compile-time computation.
Regards,
Dan McLeran _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
AFAIK, no compiler actually supports compile-time floating-point compilation, since there is no general guarantee that the same architecture would be running the program (think cross-compiles), and almost every floating-point operation is "implementation-defined", basicly, could do anything at all. Say: PPC has 128-bit long doubles, x86 only has 80-bits, but x86 internally always uses long doubles for calculations, even with 32-bit floats, and therefore gives different results than the PPC. I can't remember if those statements are accurate, but something like that goes on. You could try a factory function taking constant T's, hoping the compiler can constant-propagate through function calls (since it would be inline, it should be able to), and overload that for integral expressions? (enable_if<> should be useful here) ie: template <typename T> class bounded_t { // just a boring run-time checked version } template <int min, int max> class bounded_t<int>// and char, (un)signed char, wchar_t, etc... { // fancy compile-time version } template <typename T> bounded_t<T> bounded(const T& t, const T& min, const T& max, int dummy = disable_if<mpl::is_integral<T>, int>) { return bounded<T>(t, min, max); } template <typename T> bounded_t<T, int, int> bounded(const T& t, const T min, const T max, int dummy = enable_if<mpl::is_integral<T>, int>) { return bounded_t<T, min, max>(t); } BTW, I have NO idea whether anything like that would ever work, on any far-out plane of the universe. You have been warned.

I was thinking of exactly this kind of thing last night.One should be able to tell whether or not compile-time calculations are allowed based on template parameter T. "Simon Buchan" <simon@hand-multimedia.co.nz> wrote in message news:dh06p5$a95$1@sea.gmane.org...
Dan McLeran wrote:
let's finally do it - C++ lacks bounded types and it's high time to fix that! ;-)
I agree. I had been programming in C++ for a number of years before I was introduced to Ada. I loved the strict typing one can do in Ada and I would like to have at least some of these facilities in C++ as well (since that is what I use every day). I will certainly check out what you've posted (bounded types). One thing to keep in mind as we move forward with this is that, IMO, we need to support as much compile-time computation as much as possible. One thing I am struggling with is how to support both bounded floating-point types, but as the same time, have a bounded types template be able to be used from boost::mpl for compile-time computation.
Regards,
Dan McLeran _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
AFAIK, no compiler actually supports compile-time floating-point compilation, since there is no general guarantee that the same architecture would be running the program (think cross-compiles), and almost every floating-point operation is "implementation-defined", basicly, could do anything at all. Say: PPC has 128-bit long doubles, x86 only has 80-bits, but x86 internally always uses long doubles for calculations, even with 32-bit floats, and therefore gives different results than the PPC. I can't remember if those statements are accurate, but something like that goes on.
You could try a factory function taking constant T's, hoping the compiler can constant-propagate through function calls (since it would be inline, it should be able to), and overload that for integral expressions? (enable_if<> should be useful here) ie:
template <typename T> class bounded_t { // just a boring run-time checked version }
template <int min, int max> class bounded_t<int>// and char, (un)signed char, wchar_t, etc... { // fancy compile-time version }
template <typename T> bounded_t<T> bounded(const T& t, const T& min, const T& max, int dummy = disable_if<mpl::is_integral<T>, int>) { return bounded<T>(t, min, max); }
template <typename T> bounded_t<T, int, int> bounded(const T& t, const T min, const T max, int dummy = enable_if<mpl::is_integral<T>, int>) { return bounded_t<T, min, max>(t); }
BTW, I have NO idea whether anything like that would ever work, on any far-out plane of the universe. You have been warned.
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

| -----Original Message----- | From: boost-bounces@lists.boost.org | [mailto:boost-bounces@lists.boost.org] On Behalf Of Robert Kawulak | Sent: 22 September 2005 17:16 | To: boost@lists.boost.org | Subject: [boost] Bounded types | let's finally do it - C++ lacks bounded types and it's high time to fix. Indeed - a glaring need. I hope Boosters can agree something like this promising proposal. Paul PS I fear the _portable_ Floating point is too difficult, though I don't doubt its usefulness. I would be sad to see checked integer-ish bounded types fail because we bite off more than we can chew. Paul A Bristow Prizet Farmhouse, Kendal, Cumbria UK LA8 8AB +44 1539 561830 +44 7714 330204 mailto: pbristow@hetp.u-net.com www.hetp.u-net.com

Hi, I forgot to mention one important fact - when people talk about a bounded integer class, what they usually mean is two different matters for real: 1. A class, which doesn't allow its values to fall out of a specified range, 2. A class, for which all integer operations are safe, because it handles all the overflows etc. For the sake of universality I've decided to separate the two concepts, and my implementation focuses on the first one only, allowing also non-integral types to be used. The second concept is very difficult to implement in a portable way (as previous discussions on c.l.c++.m and c.s.c++ have shown), quite good but highly non-portable example of a class dealing with this problem can be found here: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dncode/html /secure01142004.asp. Then such SafeInt class can be used as the bounded template parameter to form a type which takes care of both the problems. The implementation of bounded templates is missing one thing - the checks of correctness of given bounds. In case of integral types there should be some compile time assertion firing when somebody tries to instantiate the template with bounds, say, 10 and 0 (which is not a valid range), in case of non-integral types there should be some logic_error exception thrown. I just can't figure out where is the best place to put the assertions, I'm afraid that this requires a little change of the design. Anyway, let me think more about it... :) Best regards, Robert

I have written something like this for signal processing application. The bounded types are integer-like. Basically, all it does it perform a check action when a value is assigned to it. The check function is specified as a template policy parameter. The version I wrote has three policies. If the assigned value is out of range, the action could 1) limit to the desired range 2) wrap the value (as if an integer of some small width) 3) throw

I have written something like this for signal processing application. The bounded types are integer-like. Basically, all it does it perform a check action when a value is assigned to it. The check function is specified as a template policy parameter. The version I wrote has three policies. If the assigned value is out of range, the action could 1) limit to the desired range 2) wrap the value (as if an integer of some small width) 3) throw
Yeah, there are all the abovementioned behaviours implemented in my version, plus ignore (for efficiency in release versions). Furthermore, in case 3 you may choose among throwing an exception, setting the ERRNO or simply ignoring the invalid operation. Of course the policies are extensible and let you specify other action than listed above. And the policies let you also pick your own ordering function used to compare values against bounds (this is especially useful when using them with non-integral types). Anyway, having experience in writing such class, could you tell if something needs changing in my implementation, or possibly if you think your implementation might be better place it somewhere to download? Best regards, Robert

----- Original Message ----- From: "Robert Kawulak" <kawulak@student.agh.edu.pl> Newsgroups: gmane.comp.lib.boost.devel Sent: Friday, September 23, 2005 7:47 AM Subject: Re: Bounded types
I have written something like this for signal processing application. The bounded types are integer-like. Basically, all it does it perform a check action when a value is assigned to it. The check function is specified as a template policy parameter. The version I wrote has three policies. If the assigned value is out of range, the action could 1) limit to the desired range 2) wrap the value (as if an integer of some small width) 3) throw
Yeah, there are all the abovementioned behaviours implemented in my version, plus ignore (for efficiency in release versions). Furthermore, in case 3 you may choose among throwing an exception, setting the ERRNO or simply ignoring the invalid operation. Of course the policies are extensible and let you specify other action than listed above. And the policies let you also pick your own ordering function used to compare values against bounds (this is especially useful when using them with non-integral types).
On this topic: Jeff Garland already has implemented something similar within the Boost date_time library called the constrained_value type. I made a variation of constrained_value, with some contribution from the Boost mailing list last year (search the archives for constrained_value). My version is here: http://www.cdiggins.com/constrained_value.hpp and some basic tests are at http://www.cdiggins.com/cv_test.cpp . My approach was to keep the policy as simple as possible and that is one which provides only the entire assignment operation (this entails the contraints checking, and exceptional behaviour), rather than breaking it down into several steps. Time constraints do not permit me to follow through on the constrained_value type submission, but I encourage you to look at and modify the code as much as you want. There is also an article about it at the C++ users journal ( http://www.cuj.com/documents/cuj0412d/ ) best of luck, Christopher Diggins http://www.cdiggins.com

Hi, In reply to Christopher Diggins post:
My version is here: http://www.cdiggins.com/constrained_value.hpp and some basic tests are at http://www.cdiggins.com/cv_test.cpp . My approach was to keep the policy as simple as possible and that is one which provides only the entire assignment operation (this entails the contraints checking, and exceptional behaviour), rather than breaking it down into several steps.
Thanks for your reply! My goal was different - to make the bounded classes and their policies as efficient and reusable as possible, even though your design is a bit similar, but simplier. The complexity of my design was the reason to create template aliases for the most common uses of basic_bounded template - this is the purpose of bounded.hpp file. Best regards, Robert

Hi group,
Some time ago I've written a set of class templates for bounded types (types whose variables may hold a value only from within a specified range).
Just today I've discovered, that basic_bounded class template is even more flexible than I thought! :-) It may be used for types holding their values not only within a specified range, but virtually any set (or, in other words, values conforming to any criterion). For instance a policy template may be written very easily for even numbers only. When it's used as basic_bounded's policy parameter, the new type will only accept even values: ------------------------------------------- template<typename T> struct even_policy; // implementation not included for conciseness typedef basic_bounded< even_policy<int> > even_int; even_int i; i = 2; // OK i = 3; // illegal i += 2; // OK i += 3; // illegal i++; // illegal, might even generate a compiler error ------------------------------------------- Therefore I think that this flexibility should be reflected in the name of the basic_bounded template as well as the library in general. Maybe it should be something like 'restricted' meaning that the types may hold only values restricted by some constraint? Or maybe 'constrained'? Could some native english speaker write which he thinks is the most appropriate name? The rest of the library doesn't need any significant changes, only more policies which seem to be useful may be added (like odd, even, etc.). Best regards, Robert

On Sun, 25 Sep 2005 22:08:32 +0200, Robert Kawulak wrote
Hi group,
Some time ago I've written a set of class templates for bounded types (types whose variables may hold a value only from within a specified range).
Just today I've discovered, that basic_bounded class template is even more flexible than I thought! :-) It may be used for types holding their values not only within a specified range, but virtually any set (or, in other words, values conforming to any criterion). For instance a policy template may be written very easily for even numbers only. When it's used as basic_bounded's policy parameter, the new type will only accept even values:
-------------------------------------------
template<typename T> struct even_policy; // implementation not included for conciseness
typedef basic_bounded< even_policy<int> > even_int; even_int i;
i = 2; // OK i = 3; // illegal i += 2; // OK i += 3; // illegal i++; // illegal, might even generate a compiler error
-------------------------------------------
Therefore I think that this flexibility should be reflected in the name of the basic_bounded template as well as the library in general. Maybe it should be something like 'restricted' meaning that the types may hold only values restricted by some constraint? Or maybe 'constrained'? Could some native english speaker write which he thinks is the most appropriate name?
Restricted is ok, but I like constrained better. Please see: http://www.boost.org/doc/html/constrained_value.html http://www.boost.org/boost/date_time/constrained_value.hpp http://www.artima.com/weblogs/viewpost.jsp?thread=79470 Jeff

Hi,
Restricted is ok, but I like constrained better. Please see:
http://www.boost.org/doc/html/constrained_value.html http://www.boost.org/boost/date_time/constrained_value.hpp http://www.artima.com/weblogs/viewpost.jsp?thread=79470
Jeff
Thank you very much for the links, they inspired me to think deeply about the design of my class once again :). What I meant to create was pretty similar to constrained_value, only more complex, more general and maybe a little more efficient. BTW, constrained_value of Christofer Diggins has at least one 'bug' - it has a default constructor which default-initialises the value, and doesn't check if this default value conforms to the constraints. I also believe, that it'd be better to supply operator const value() than operator value() - this conversion is implicit so the const version would be safer. Best regards, Robert

On Mon, 26 Sep 2005 01:02:25 +0200, Robert Kawulak wrote
Hi,
Restricted is ok, but I like constrained better. Please see:
http://www.boost.org/doc/html/constrained_value.html http://www.boost.org/boost/date_time/constrained_value.hpp http://www.artima.com/weblogs/viewpost.jsp?thread=79470
Jeff
Thank you very much for the links, they inspired me to think deeply about the design of my class once again :). What I meant to create was pretty similar to constrained_value, only more complex, more general and maybe a little more efficient.
Good -- it seemed like alot of the thinking in this thread (which I've really only been skimming, so perhaps this is unfair) hadn't been considering prior art. Just so you know, it's my feeling that the 'range constraint' is the most frequent and most of the more complicated cases you can imagine don't come up that much in practice. I'm not even sure it's really worth supporting. The most important thing is to allow customization of the error handling and set it up so the details of the constraint violation can (eg: min or max) can be determined. Again I've been skimming so I don't know if your code does this or not. One other thought. The constrained value type fits into a 'value programming' classification that eventually I'd like to see expanded in boost. Some other parts of this include wrapping_int which has a range and wraps around when you do math with it, integer_adapters which adds infinites and null values to ints. I have a "super enumeration class" (never posted) that fits into this category and I know a couple others have been proposed on the list which is a related concept. If you haven't already have a look at http://www.two-sdg.demon.co.uk/curbralan/papers/ObjectsOfValue.pdf for some broader thoughts on this subject. Anyway, I've seen using these small value types really cleanup what would otherwise be ugly and messy code.
BTW, constrained_value of Christofer Diggins has at least one 'bug' - it has a default constructor which default-initialises the value, and doesn't check if this default value conforms to the constraints.
That's not good. I guess you'd need need one of the policies to specify the default value if it is allowed. In the date-time constrained_value there is no default constructor as I recall.
I also believe, that it'd be better to supply operator const value() than operator value() - this conversion is implicit so the const version would be safer.
Yep. Jeff

Hi,
Just so you know, it's my feeling that the 'range constraint' is the most frequent and most of the more complicated cases you can imagine don't come up that much in practice. I'm not even sure it's really worth supporting.
It seems to be the most frequent and most important, but I think we shouldn't close the door for the other not-so-common-yet-occuring-from-time-to-time constraints, because it's easy to let them work. One day you may need to have a type for odd numbers only, for lowercase strings only or for strings containing numbers only, and the template will be ready here :)
The most important thing is to allow customization of the error handling and set it up so the details of the constraint violation can (eg: min or max) can be determined. Again I've been skimming so I don't know if your code does this or not.
Customisation of the error handling - yes, reporting details of constraints violation - not implemented, but very easily supported.
That's not good. I guess you'd need need one of the policies to specify the default value if it is allowed. In the date-time constrained_value there is no default constructor as I recall.
Right, in my implementation if you want to use default construction, the policy must supply initialize() member for this purpose. Best regards, Robert

From: "Jeff Garland" <jeff@crystalclearsoftware.com>
On Mon, 26 Sep 2005 01:02:25 +0200, Robert Kawulak wrote
Restricted is ok, but I like constrained better. Please see:
Agreed.
One other thought. The constrained value type fits into a 'value programming' classification that eventually I'd like to see expanded in boost. Some other parts of this include wrapping_int which has a range and wraps around when you do math with it
It sounds like--I've not looked at either class to know whether this is reasonable--wrapping_int's behavior could be subsumed by constrained_value. That is, Robert's class could determine the new value to store based upon calling a policy function. If that function determines that the new value is out of range, then it can wrap the value or otherwise adjust it, or it can signal an error. Such an approach could actually permit incrementing a constrained_value that only permits odd numbers. That is, incrementing would increment to the next odd number. (To support that would require a fatter policy interface, I expect, so I'm not saying it would necessarily be a good idea.) -- Rob Stewart stewart@sig.com Software Engineer http://www.sig.com Susquehanna International Group, LLP using std::disclaimer;

Hi,
From: Rob Stewart <...> It sounds like--I've not looked at either class to know whether this is reasonable--wrapping_int's behavior could be subsumed by constrained_value. That is, Robert's class could determine the new value to store based upon calling a policy function. If that function determines that the new value is out of range, then it can wrap the value or otherwise adjust it, or it can signal an error.
This is exactly how it works :)
Such an approach could actually permit incrementing a constrained_value that only permits odd numbers. That is, incrementing would increment to the next odd number. (To support that would require a fatter policy interface, I expect, so I'm not saying it would necessarily be a good idea.)
The policy interface is indeed fatter, it contains the following five functions (the version I'm currently working on, not published yet): initialize() - returns a value used to default-initialize a constrained object; is_valid_value(value) - returns false if assignment of the value to a constrained object would be an error (used to verify if a value input from a stream is correct); assign(variable, new_value) - performs assignment of new_value to the variable holding the value of a constrained object; increment(variable) - increments the variable holding the value of a constrained object; decrement(variable) - decrements the variable holding the value of a constrained object. increment() and decrement() are added for efficiency reasons (in case of bounded types you need only one comparison and increment/decrement instead of addition, two comparisons and assignment). However, there are no policy functions for +=, *= etc. - this would make the whole constrained types thing too messy. Increment and decrement are just so common, and the efficiency gain seems to be significant enough, that I've decided to put them there. BTW in the current version I've changed the name of basic_bounded template to constrained_type (I don't like constrained_value name which may be misleading, because it's a type of values rather than a value itself), and named the library constrained_types. I'm refactoring the design a little, adding some additional functionality and hope to publish it soon, and maybe submit for a formal review if people like it :) Best regards, Robert

From: "Robert Kawulak" <kawulak@student.agh.edu.pl>
From: Rob Stewart
The policy interface is indeed fatter, it contains the following five functions (the version I'm currently working on, not published yet): initialize() - returns a value used to default-initialize a constrained object;
It seems that you'd want it to take a non-const reference to avoid copying.
is_valid_value(value) - returns false if assignment of the value to a constrained object would be an error (used to verify if a value input from a stream is correct);
I think "is_valid" is sufficient.
assign(variable, new_value) - performs assignment of new_value to the variable holding the value of a constrained object; increment(variable) - increments the variable holding the value of a constrained object; decrement(variable) - decrements the variable holding the value of a constrained object.
increment() and decrement() are added for efficiency reasons (in case of bounded types you need only one comparison and increment/decrement instead of addition, two comparisons and assignment). However, there are no policy functions for +=, *= etc. - this would make the whole constrained types thing too messy. Increment and decrement are just so common, and the efficiency gain seems to be significant enough, that I've decided to put them there.
BTW in the current version I've changed the name of basic_bounded template to constrained_type (I don't like constrained_value name which may be misleading, because it's a type of values rather than a value itself), and
I'm confused. I thought the whole point of your library was to create an object that *has* a value and to constrain that value to be a member of a prescribed set. That's how you can add them together, increment them, etc. Thus, "constrained_value" is exactly the right name. Given that, you do need to implement, though not necessarily through the policy class, the arithmetic assignment operators, and everything else that will make these act like built-in types. -- Rob Stewart stewart@sig.com Software Engineer http://www.sig.com Susquehanna International Group, LLP using std::disclaimer;

On 09/28/2005 09:33 AM, Rob Stewart wrote: [snip]
I'm confused. I thought the whole point of your library was to create an object that *has* a value and to constrain that value to be a member of a prescribed set. That's how you can add them together, increment them, etc. Thus, "constrained_value" is exactly the right name.
This sounds *almost* like the range_all mentioned in: http://article.gmane.org/gmane.comp.lib.boost.devel/117761 The difference, AFAICT, as that each element is the "prescribed set" is an enumeration instead of some contiguous subset of an integral value like int or long. Maybe the common parts could be factored out? I could re-upload the range_all.zip to the vault if you're interested.

Hi,
This sounds *almost* like the range_all mentioned in:
http://article.gmane.org/gmane.comp.lib.boost.devel/117761
The difference, AFAICT, as that each element is the "prescribed set" is an enumeration instead of some contiguous subset of an integral value like int or long.
Maybe the common parts could be factored out? I could re-upload the range_all.zip to the vault if you're interested.
OK, please let me know how and when I can download it - I'll have a look at this. Best regards, Robert

On 09/29/2005 01:35 AM, Robert Kawulak wrote: [snip]
Maybe the common parts could be factored out? I could re-upload the range_all.zip to the vault if you're interested.
OK, please let me know how and when I can download it - I'll have a look at this.
Just uploaded to http://www.boost-consulting.com/vault in the Template Metaprogramming directory in range_all.zip. -regards, Larry

On 09/29/2005 07:15 AM, Larry Evans wrote: [snip]
Just uploaded to http://www.boost-consulting.com/vault in the Template Metaprogramming directory in range_all.zip.
To test the above, you may also need to rerun: libs/mpl/preprocessed/preprocess.py *after* changing: boost/mpl/aux_/sequence_wrapper.hpp to that in: http://cvs.sourceforge.net/viewcvs.py/boost-sandbox/boost-sandbox/boost/mpl/... For reasons, please see: http://aspn.activestate.com/ASPN/Mail/Message/boost/2640803 -best regards, Larry

Hi,
initialize() - returns a value used to default-initialize a constrained object;
It seems that you'd want it to take a non-const reference to avoid copying.
I'm afraid i don't understand what you mean...
BTW in the current version I've changed the name of basic_bounded template to constrained_type (I don't like constrained_value name which may be misleading, because it's a type of values rather than a value itself), and
I'm confused. I thought the whole point of your library was to create an object that *has* a value and to constrain that value to be a member of a prescribed set. That's how you can add them together, increment them, etc. Thus, "constrained_value" is exactly the right name.
Putting it simply, point of my library is to provide templates of classes of objects having a value conforming to given constraints. constrained_type (or whatever we'll call it) is a type (class template to be strict), how can a type be named "something_value"? Now that's confusing to me... Maybe constrained_values_type would be the most appropriate ;-)
Given that, you do need to implement, though not necessarily through the policy class, the arithmetic assignment operators, and everything else that will make these act like built-in types.
Actuallny I did, all the mutating operators are overloaded: increment/decrement use adequate policy functions, and the rest (all the @= operators) use policy member assign(). Best regards, Robert

From: "Robert Kawulak" <kawulak@student.agh.edu.pl>
initialize() - returns a value used to default-initialize a constrained object;
It seems that you'd want it to take a non-const reference to avoid copying.
I'm afraid i don't understand what you mean...
Use void initialize(value_type & value_o); rather than value_type initialize(); Thus, when passed the data member to initialize, it can initialize that object directly. Granted, (N)RVO can often avoid the copy, but this change will ensure you get the efficiency.
BTW in the current version I've changed the name of basic_bounded template to constrained_type (I don't like constrained_value name which may be misleading, because it's a type of values rather than a value itself), and
I'm confused. I thought the whole point of your library was to create an object that *has* a value and to constrain that value to be a member of a prescribed set. That's how you can add them together, increment them, etc. Thus, "constrained_value" is exactly the right name.
Putting it simply, point of my library is to provide templates of classes of objects having a value conforming to given constraints. constrained_type (or whatever we'll call it) is a type (class template to be strict), how can a type be named "something_value"? Now that's confusing to me... Maybe constrained_values_type would be the most appropriate ;-)
What you are suggesting is equivalent to suggesting that std::vector should be named "vector_type" because it is a class template. The purpose of the class template is to create objects through instantiating specializations. It is those objects that are actually used. Thus, the type name should be indicative of the purpose and use of those objects. Those objects are values. The class name should indicate the value nature of those objects. -- Rob Stewart stewart@sig.com Software Engineer http://www.sig.com Susquehanna International Group, LLP using std::disclaimer;

Hi,
Use
void initialize(value_type & value_o);
rather than
value_type initialize();
Thus, when passed the data member to initialize, it can initialize that object directly. Granted, (N)RVO can often avoid the copy, but this change will ensure you get the efficiency.
I don't think so, because your version of initialize couldn't be used to initialize a value in constructor's initialization list. So first the value would be default-constructed, and then assigned another value using initialize. In bounded policies I use passed_value_type initialize() where passed_value_type is value_type for integral types and const value_type & for other types. The second returns a reference to a static object - that's the most efficient method I can think of, initialization takes only one copy-construction (for details please look into the code).
Putting it simply, point of my library is to provide templates of classes of objects having a value conforming to given constraints. constrained_type (or whatever we'll call it) is a type (class template to be strict), how can a type be named "something_value"? Now that's confusing to me... Maybe constrained_values_type would be the most appropriate ;-)
What you are suggesting is equivalent to suggesting that std::vector should be named "vector_type" because it is a class template.
The purpose of the class template is to create objects through instantiating specializations. It is those objects that are actually used. Thus, the type name should be indicative of the purpose and use of those objects. Those objects are values. The class name should indicate the value nature of those objects.
Uhh, maybe you're right ;-) I don't know why, but it just "byte my eyes" when I see a type named "something_value"... Nevermind, if people here really resist that it should be called constrained_value instead of constrained_type, then OK - I'll change it. Best regards, Robert

Robert Kawulak wrote:
Hi,
[sig?]
Use
void initialize(value_type & value_o);
rather than
value_type initialize();
Thus, when passed the data member to initialize, it can initialize that object directly. Granted, (N)RVO can often avoid the copy, but this change will ensure you get the efficiency.
I don't think so, because your version of initialize couldn't be used to initialize a value in constructor's initialization list. So first the value would be default-constructed, and then assigned another value using initialize. In bounded policies I use passed_value_type initialize() where passed_value_type is value_type for integral types and const value_type & for other types. The second returns a reference to a static object - that's the most efficient method I can think of, initialization takes only one copy-construction (for details please look into the code).
ref to static? It feels cludgy. Just trust the RVO even for user classes, IMHO, it's how the std lib works. Unfortunately the RVO can't get rid of the side-effects of c/d'tors, so you should make sure it's documented that values must have normal copy semantics if default initialisation is used. <snip>
What you are suggesting is equivalent to suggesting that std::vector should be named "vector_type" because it is a class template.
The purpose of the class template is to create objects through instantiating specializations. It is those objects that are actually used. Thus, the type name should be indicative of the purpose and use of those objects. Those objects are values. The class name should indicate the value nature of those objects.
Uhh, maybe you're right ;-) I don't know why, but it just "byte my eyes" when I see a type named "something_value"... Nevermind, if people here really resist that it should be called constrained_value instead of constrained_type, then OK - I'll change it.
Why not just 'constrained'? ie. constrained<int>?

Hi,
From: Simon Buchan
[sig?]
What's this?
In bounded policies I use passed_value_type initialize() where passed_value_type is value_type for integral types and const value_type & for other types. The second returns a reference to a static object - that's the most efficient method I can think of, initialization takes only one copy-construction (for details please look into the code).
ref to static? It feels cludgy.
It's not a static created only for initialisations. Bounds specifier's functions min_value() and max_value() create function-scope static objects and return them, this way the objects aren't being created every time the functions are called (and they're called very often, so I think this is reasonable for non-integral types). And initialize() only returns min_value() and that's it.
Uhh, maybe you're right ;-) I don't know why, but it just "byte my eyes" when I see a type named "something_value"... Nevermind, if people here really resist that it should be called constrained_value instead of constrained_type, then OK - I'll change it.
Why not just 'constrained'? ie. constrained<int>?
Sounds good, and how to call the library? 'constrained_types'? Best regards, Robert

On Thu, 29 Sep 2005 08:32:24 +0200, Robert Kawulak wrote
Uhh, maybe you're right ;-) I don't know why, but it just "byte my eyes" when I see a type named "something_value"... Nevermind, if people here really resist that it should be called constrained_value instead of constrained_type, then OK - I'll change it.
Why not just 'constrained'? ie. constrained<int>?
Sounds good, and how to call the library? 'constrained_types'?
When I called it constrained_value I did that b/c the types that could be create d with it are all value types. In retrospect, constrained_int might have been more accurate for my class. For what you're working on, I think constrained_type or just plain constrained would probably be fine too. Jeff

From: "Robert Kawulak" <kawulak@student.agh.edu.pl>
From: Simon Buchan
[sig?]
What's this?
My guess is he's calling your attention to the lost attribution.
In bounded policies I use passed_value_type initialize() where passed_value_type is value_type for integral types and const value_type & for other types. The second returns a reference to a static object - that's the most efficient method I can think of, initialization takes only one copy-construction (for details please look into the code).
ref to static? It feels cludgy.
It's not a static created only for initialisations. Bounds specifier's functions min_value() and max_value() create function-scope static objects and return them, this way the objects aren't being created every time the functions are called (and they're called very often, so I think this is reasonable for non-integral types). And initialize() only returns min_value() and that's it.
Once you go with a function local static, you have to worry about thread safety. In the simpler range bounded approach, the type includes the boundaries, so there's no need for statics. It would only be the more complicated bounding policies that might have need for this behavior. Thus, don't force the creation of statics in your design. Ensure that if they are used, it is the choice of the policy writer.
Uhh, maybe you're right ;-) I don't know why, but it just "byte my eyes" when I see a type named "something_value"... Nevermind, if people here really resist that it should be called constrained_value instead of constrained_type, then OK - I'll change it.
Why not just 'constrained'? ie. constrained<int>?
Sounds good, and how to call the library? 'constrained_types'?
The library name should probably be "Constrained," the namespace, "constraineds," and the type, "constrained," if you go this route. (That's in keeping with Boost.Tuple, which uses the "tuples" namespace and the "tuple" type.) If you call it the "Constrained Types" library, and use the namespace "constrained_types," does "constrained" for the type name fit with Boost prior art and intention? Those names sound a lot better, so that may be sufficient justification, but I don't want to presume this approach is acceptable to Boost as a whole. -- Rob Stewart stewart@sig.com Software Engineer http://www.sig.com Susquehanna International Group, LLP using std::disclaimer;

Hi,
From: Rob Stewart
[sig?]
What's this?
My guess is he's calling your attention to the lost attribution.
Ah, sorry! Now I'll remember. :)
It's not a static created only for initialisations. Bounds specifier's functions min_value() and max_value() create function-scope static objects and return them, this way the objects aren't being created every time the functions are called (and they're called very often, so I think this is reasonable for non-integral types). And initialize() only returns min_value() and that's it.
Once you go with a function local static, you have to worry about thread safety.
Even though the local statics are constant? Then the only problem would be initialisation, but doesn't compiler take a proper care of this in multi-threaded implementation?
In the simpler range bounded approach, the type includes the boundaries, so there's no need for statics. It would only be the more complicated bounding policies that might have need for this behavior. Thus, don't force the creation of statics in your design. Ensure that if they are used, it is the choice of the policy writer.
Well, it's not forced - one may easily supply his own bounds specifying policy that pass bounds by value. Actually, in my implementation it depends on the underlying type. If it's integral, then bounds are returned by value. If it's not, the min_value() function looks something like this: static const value_type & min_value() { static const value_type v = MinValueGenerator()(); return v; } Is there really something that wrong with this design? Is there any danger out there because of using function-scope const static object? It just seemed much better to me - the value is constructed only once, and every next time min_value() takes only one comparison (static initialisation check) and returning a reference. In return-by-value case every call results in: 1) creation of generator object (in most cases optimised away) 2) call of generator's call operator which results in construction of new object 3) copying the object on return and destructing it (may be optimised away by RVO, but not always) 4) eventually copying and destructing the object again and again as it's passed by value *) using the object, for example when comparing it with the value you try to assign to check whether the value lays within bounds, in every assign there are two such checks - multiply all the operations by 2 5) destructing the object I can see no con in using function-scope const statics here and a huge pro - efficiency. And I don't consider it as premature optimisation - it rather seems to me as avoiding premature pessimisation.
Why not just 'constrained'? ie. constrained<int>?
Well, this wouldn't be constrained<int> but constrained< bounded_policies::error< bounds_specifiers::static_bounds<int, 0, 10> > > :) But I like the concise name 'constrained' anyway.
The library name should probably be "Constrained," the namespace, "constraineds," and the type, "constrained," if you go this route. (That's in keeping with Boost.Tuple, which uses the "tuples" namespace and the "tuple" type.)
If you call it the "Constrained Types" library, and use the namespace "constrained_types," does "constrained" for the type name fit with Boost prior art and intention? Those names sound a lot better, so that may be sufficient justification, but I don't want to presume this approach is acceptable to Boost as a whole.
For me the latters also sound better, what do you people think? Best regards, Robert

From: "Robert Kawulak" <kawulak@student.agh.edu.pl>
From: Rob Stewart
Once you go with a function local static, you have to worry about thread safety.
Even though the local statics are constant? Then the only problem would be initialisation, but doesn't compiler take a proper care of this in multi-threaded implementation?
No.
In the simpler range bounded approach, the type includes the boundaries, so there's no need for statics. It would only be the more complicated bounding policies that might have need for this behavior. Thus, don't force the creation of statics in your design. Ensure that if they are used, it is the choice of the policy writer.
Well, it's not forced - one may easily supply his own bounds specifying policy that pass bounds by value.
I don't understand. So long as the comparison against the boundaries is a comparison against a constant, then the code will be efficient and there's no need for statics.
Actually, in my implementation it depends on the underlying type. If it's integral, then bounds are returned by value. If it's not, the min_value() function looks something like this:
static const value_type & min_value() { static const value_type v = MinValueGenerator()(); return v; }
Is there really something that wrong with this design? Is there any danger
I see what you're doing. Why not: void validate(value_type & value_io); That function can do the validation any way it sees fit and enables the discontinuous ranges you spoke of previously.
out there because of using function-scope const static object? It just seemed much better to me - the value is constructed only once, and every next time min_value() takes only one comparison (static initialisation check) and returning a reference. In return-by-value case every call results
Don't forget that using the function local static, aside form the MT problem, has overhead. The implementation does, in effect example() { int (in-platform-specific-location) result; if (!compiler-specific-flag) { result = initial-value; compiler-specific-flag = true; } } when you write this: example() { static int result(initial-value); }
in: 1) creation of generator object (in most cases optimised away) 2) call of generator's call operator which results in construction of new object 3) copying the object on return and destructing it (may be optimised away by RVO, but not always) 4) eventually copying and destructing the object again and again as it's passed by value *) using the object, for example when comparing it with the value you try to assign to check whether the value lays within bounds, in every assign there are two such checks - multiply all the operations by 2 5) destructing the object
I can see no con in using function-scope const statics here and a huge pro - efficiency. And I don't consider it as premature optimisation - it rather seems to me as avoiding premature pessimisation.
All of those points are based upon your design. If you use the validate() approach, you avoid all of that and can check for both the minimum and maximum range at once, if that's appropriate. (I haven't looked at your code, I haven't thought through the design issues, etc., so what I propose may not be possible. I leave it to you to consider the idea.)
Well, this wouldn't be constrained<int> but constrained< bounded_policies::error< bounds_specifiers::static_bounds<int, 0, 10> > >
That's nasty. Do you need things separated like that? It would be easier to use (though maybe less flexible in some important way) with this: constrained<bounded<int, 0, 10> > -- Rob Stewart stewart@sig.com Software Engineer http://www.sig.com Susquehanna International Group, LLP using std::disclaimer;

Hi,
From: Rob Stewart
Once you go with a function local static, you have to worry about thread safety.
Even though the local statics are constant? Then the only problem would be initialisation, but doesn't compiler take a proper care of this in multi-threaded implementation?
No.
:-/ (the world is so cruel :P)
Thus, don't force the creation of statics in your design. Ensure that if they are used, it is the choice of the policy writer.
Well, it's not forced - one may easily supply his own bounds specifying policy that pass bounds by value.
I don't understand. So long as the comparison against the boundaries is a comparison against a constant, then the code will be efficient and there's no need for statics.
In case of integrals - yes, and that's how it's done. I was talking about the UDTs case - then no, because every time these constants have to be constructed first, then used in comparison. By using statics I avoid constructing them every time a comparison is done.
static const value_type & min_value() { static const value_type v = MinValueGenerator()(); return v; }
Is there really something that wrong with this design? Is there any danger
I see what you're doing. Why not:
void validate(value_type & value_io);
That function can do the validation any way it sees fit and enables the discontinuous ranges you spoke of previously.
This is exactly the way constrained policies' assign function works (it takes the value and decides whether it's correct), but we're one layer below :) And here, unfortunately, there are more tests that have to be done, not only !(value < min_value || max_value < value): in increment: value < max_value in decrement: min_value < value in wrapping and clipping policies' assign: value < min_value and in other place max_value < value And I'm afraid it doesn't depend on the design, it's just maths.
the value is constructed only once, and every next time min_value() takes only one comparison (static initialisation check) and returning a reference. In return-by-value case every call results
Don't forget that using the function local static, aside form the MT problem, has overhead. The implementation does, in effect
example() { int (in-platform-specific-location) result; if (!compiler-specific-flag) { result = initial-value; compiler-specific-flag = true; } }
when you write this:
example() { static int result(initial-value); }
I didn't forget about it, this is what I meant by saying "comparison (static initialisation check)"
Well, this wouldn't be constrained<int> but constrained< bounded_policies::error< bounds_specifiers::static_bounds<int, 0, 10> > >
That's nasty. Do you need things separated like that? It would be easier to use (though maybe less flexible in some important way) with this:
constrained<bounded<int, 0, 10> >
This is the reason why shortcut aliases are also provided for the most common cases, so you can write: bounded_int<int, 0, 10>::type to get exactly the same effect. It's just like with string that stays for basic_string< char, char_traits<char>, allocator<char> > and it's very flexible yet very simple in the most common cases. Best regards, Robert

From: "Robert Kawulak" <kawulak@student.agh.edu.pl>
From: Rob Stewart
I see what you're doing. Why not:
void validate(value_type & value_io);
That function can do the validation any way it sees fit and enables the discontinuous ranges you spoke of previously.
This is exactly the way constrained policies' assign function works (it takes the value and decides whether it's correct), but we're one layer below :) And here, unfortunately, there are more tests that have to be done, not only !(value < min_value || max_value < value): in increment: value < max_value in decrement: min_value < value in wrapping and clipping policies' assign: value < min_value and in other place max_value < value And I'm afraid it doesn't depend on the design, it's just maths.
I disagree. See below. If you intend to support discontinuous ranges, then what you've described won't work. For example, checking whether the new value is less than the maximum isn't appropriate for incrementing if the policy is enforcing, say, odd numbers. One approach is to simply increment the current value and then call validate(). validate() can decide what to do, including modifying the value. Unfortunately, for the odd numbers policy, that's also insufficient, since validate() would need to know whether to add or subtract one to get to the next odd number in the direction the caller intended. So, it seems that the policy must implement validated assignment, incrementing, and decrementing. You can build the rest of the behavior on that. Your type can hold the value and rely on the policy to assign, increment, and decrement. You can use boost::call_traits to get optimal argument passing for assign(): void assign(value_type & value_o, typename boost::call_traits<value_type>::param_type value_i); The increment() and decrement() functions don't need to worry about that: void decrement(value_type & value_io); void increment(value_type & value_io); BTW, it might also be important to defer copying to a copying policy class to account for polymorphic types. Have I missed something important in the behavior you intend? -- Rob Stewart stewart@sig.com Software Engineer http://www.sig.com Susquehanna International Group, LLP using std::disclaimer;

Hi,
From: Rob Stewart
This is exactly the way constrained policies' assign function works (it takes the value and decides whether it's correct), but we're one layer below :) And here, unfortunately, there are more tests that have to be done, not only !(value < min_value || max_value < value): in increment: value < max_value in decrement: min_value < value in wrapping and clipping policies' assign: value < min_value and in other place max_value < value And I'm afraid it doesn't depend on the design, it's just maths.
I disagree. See below.
If you intend to support discontinuous ranges, then what you've described won't work. For example, checking whether the new value is less than the maximum isn't appropriate for incrementing if the policy is enforcing, say, odd numbers.
Oh, but I was talking only about how bounded policies work! Of course I know that the behaviour for, say, odd policy would be different, and discontinuous ranges ARE supported, I just wasn't talking about them.
So, it seems that the policy must implement validated assignment, incrementing, and decrementing. You can build the rest of the behavior on that. Your type can hold the value and rely on the policy to assign, increment, and decrement.
And that's exactly how it's done, but you still haven't look into the code, have you? ;-) This discussion seems to be pointless unless you do so...
You can use boost::call_traits to get optimal argument passing for assign():
void assign(value_type & value_o, typename boost::call_traits<value_type>::param_type value_i);
The increment() and decrement() functions don't need to worry about that:
void decrement(value_type & value_io);
void increment(value_type & value_io);
Please do look into the code :) Or better, wait 'till tomorrow or the day after, the newest version should be available then. Best regards, Robert

From: "Robert Kawulak" <kawulak@student.agh.edu.pl>
From: Rob Stewart
This is exactly the way constrained policies' assign function works (it takes the value and decides whether it's correct), but we're one layer below :) And here, unfortunately, there are more tests that have to be done, not only !(value < min_value || max_value < value): in increment: value < max_value in decrement: min_value < value in wrapping and clipping policies' assign: value < min_value and in other place max_value < value And I'm afraid it doesn't depend on the design, it's just maths.
I disagree. See below.
If you intend to support discontinuous ranges, then what you've described won't work. For example, checking whether the new value is less than the maximum isn't appropriate for incrementing if the policy is enforcing, say, odd numbers.
Oh, but I was talking only about how bounded policies work! Of course I know that the behaviour for, say, odd policy would be different, and discontinuous ranges ARE supported, I just wasn't talking about them.
I'm sorry. I didn't recognize that you were talking about individual policies and not the constrained_value type itself. Still, I don't see the need for what you're discussing for all types. All you need are compile time constants for the minimum and maximum and then access those. Yes, that means the code differs for types that can be used as template arguments and those that don't (different specializations), but that eliminates the overhead for what should be a common case.
And that's exactly how it's done, but you still haven't look into the code, have you? ;-) This discussion seems to be pointless unless you do so... [snip] Please do look into the code :) Or better, wait 'till tomorrow or the day after, the newest version should be available then.
I looked at it briefly. It doesn't have bearing on this point I was trying to make. However, having looked at your code now will help me to avoid suggesting what you're already done (based upon previous messages in the thread, I had been under the impression that you had far less implemented than you do). -- Rob Stewart stewart@sig.com Software Engineer http://www.sig.com Susquehanna International Group, LLP using std::disclaimer;

Hi,
From: Rob Stewart However, having looked at your code now will
Remember the new version is now in a different place: http://student.agh.edu.pl/~kawulak/ct.zip, and I've changed the thread's topic to that starting with [constrained_types]. Best regards, Robert

| -----Original Message----- | From: boost-bounces@lists.boost.org | [mailto:boost-bounces@lists.boost.org] On Behalf Of Robert Kawulak | Sent: 29 September 2005 20:26 | To: boost@lists.boost.org | Subject: Re: [boost] Bounded types (or maybe not 'bounded' | anymore? ;-) | | > The library name should probably be "Constrained," the | > namespace, "constraineds," and the type, "constrained," if you go | > this route. (That's in keeping with Boost.Tuple, which uses the | > "tuples" namespace and the "tuple" type.) | > | > If you call it the "Constrained Types" library, and use the | > namespace "constrained_types," does "constrained" for the type | > name fit with Boost prior art and intention? Those names sound a | > lot better, so that may be sufficient justification, but I don't | > want to presume this approach is acceptable to Boost as a whole. | | For me the latters also sound better, what do you people think? I think these short, unabbreviated but accurate names sound good, and fit with established names. Also I am sure I am not alone in being encouraged by the progress so far - but Boost needs this to be _FINISHED_ including the documentation (including acknowledgement to the several previous but not quite finished contributions, and rationale), tests and EXAMPLES of use. If this can be achieved, it will be most valuable, and probably can be retrofitted in several existing libraries. Paul Paul A Bristow Prizet Farmhouse, Kendal, Cumbria UK LA8 8AB +44 1539 561830 +44 7714 330204 mailto: pbristow@hetp.u-net.com www.hetp.u-net.com

Hi, The new, almost finished constrained_types library is here: http://student.agh.edu.pl/~kawulak/ct.zip. It's later than I promised, but recently I didn't have much time and I just wanted to polish it before publishing. I successfully compiled it with the following compilers: gcc 4.0.0 (Djgpp) gcc 3.4.2 (MinGW) Borland C++ 5.6.4 Microsoft C++ 13.10.3077 Digital Mars 8.45c
From: Paul A Bristow | > If you call it the "Constrained Types" library, and use the | > namespace "constrained_types," does "constrained" for the type | > name fit with Boost prior art and intention? Those names sound a | > lot better, so that may be sufficient justification, but I don't | > want to presume this approach is acceptable to Boost as a whole. | | For me the latters also sound better, what do you people think?
I think these short, unabbreviated but accurate names sound good, and fit with established names.
I didn't change the name of constrained_type template to constrained yet, but if this shorter form is OK then I'll do this before next update.
Also I am sure I am not alone in being encouraged by the progress so far - but Boost needs this to be _FINISHED_ including the documentation (including acknowledgement to the several previous but not quite finished contributions, and rationale), tests and EXAMPLES of use.
I'm still working on it :) Currently I'm working on better tests and examples, but for now included test.cpp must suffice. Documentation so far is only in the form of code comments, I'll take care of this later.
From: Larry Evans
Just uploaded to http://www.boost-consulting.com/vault in the Template Metaprogramming directory in range_all.zip.
I looked into the code, but I must say I'm far from being an mpl expert and I had difficulties with understanding the code ;-) Maybe you could look into my code and figure out if it could be reused? As to the function-local static objects - I've created another bounds specifier class which doesn't create any statics and made it the default, the static version is still available though. And another thing, which is quite important and many people may ask about this - why bounded_int and the like doesn't take only MinValue and MaxValue parameters and deduce the underlying type to be the smallest type that can hold both the values? At first I also thought it's a very good idea, I even implemented integral_bounds wrapper for autoamtic type selection. But then I came to conclusion that automatic type selection can more harm than help. Consider such situation: let's assume that unsigned char's range is <0, 255> and you want to create bounded_int<0, 255>. What underlying type would be used? That would be unsigned char. That's great, this is what we wanted - no space is wasted, the automatic type selection has chosen the most appropriate type. But this bounded type is useless for any operations other than incrementing/decrementing! If we try to assign any out-of-bounds value, it'll be truncated to unsigned char before assignment, and the assigned temporary will of course lay within bounds - from the point of view of bounded_int everything's OK. To avoid the problem of overflows, we could select some type larger than unsigned char, on which one can perform the wanted operations without overflows. But how much larger? It depends on the operations one's going to perform. But howcome the auto type selection mechanism is supposed to know how much is "enough" for us? It can't, and therefore I think that type selection should be a conscious decision of a programmer, not left to any magical wizard. Making the automatic type selection mechanism select a type at least twice as big as needed could be a solution. This way we can protect ourselves against overflows in most situations. But unfortunately not all, and so I'm also afraid that using such mechanism could be a bad idea because a programmer who uses it, assuming it's safe in "most situations", could forget about situations in which it's not and write code which does contain overflows. The best (and only, I think) way to avoid any overflows is to use some unlimited range integer class as the underlying type (like ::std::N1744::integer or mentioned somewhere big_int). A little worse solution, that doesn't allow to avoid overflows, but at least signals them by throwing an exception, is to use a safe integer class (similar to safe_int described at http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dncode/html /secure01142004.asp). The problem with these solutions is that they both aren't available in Standard C++ nor in Boost yet. Best regards, Robert

Hi everybody,
From: Robert Kawulak I didn't change the name of constrained_type template to constrained yet, but if this shorter form is OK then I'll do this before next update.
I'm considering some changes in naming, in particular: - I'd change 'constrained_type' to 'constrained', - I wonder if I should move 'constrained' and its aliases ('boounded_int' etc.) up form 'boost::constrained_types' namespace directly to 'boost' namespace - these are things that are most likely to be used and maybe 'boost' is better for them (or maybe, instead of moving them, using declarations in 'boost' will suffice), - the bounds specifiers are in 'boost::constrained_types::bounds_specifiers' namespace, so maybe there's no need to add '_bounds' to each name at the end: bounds_specifiers::integral_bounds -> bounds_specifiers::integral bounds_specifiers::generated_bounds -> bounds_specifiers::generated bounds_specifiers::static_bounds -> bounds_specifiers::static - OTOH, the bounded policies' names seem to be to short and not properly chosen, I'd change their names so they say what the policy does when an attempt is made to assign an out-of-bounds value: bounded_policies::error -> bounded_policies::failing bounded_policies::wrap -> bounded_policies::wrapping bounded_policies::clip -> bounded_policies::clipping - maybe changing the namespaces' names from plural to singular would make the names of policies more meaningful: error_policies::throw_exception -> error_policy::throw_exception bounded_policies::error -> bounded_policy::failing bounds_specifiers::static_bounds -> bounds_specifier::static (Note: all the abovementioned namespaces reside in 'boost::constrained_types') I'd appreciate any comments, especially of people experienced in the area of naming conventions :) Best regards, Robert

On Wed, 5 Oct 2005 11:32:39 +0200, Robert Kawulak wrote
Hi everybody,
From: Robert Kawulak I didn't change the name of constrained_type template to constrained yet, but if this shorter form is OK then I'll do this before next update.
I'm considering some changes in naming, in particular:
- I'd change 'constrained_type' to 'constrained',
- I wonder if I should move 'constrained' and its aliases ('boounded_int' etc.) up form 'boost::constrained_types' namespace directly to 'boost' namespace - these are things that are most likely to be used and maybe 'boost' is better for them (or maybe, instead of moving them, using declarations in 'boost' will suffice),
I wouldn't put things directly into the boost namespace. It's not a big deal for people to get used to using or aliasing boost::constrained_types.
- the bounds specifiers are in 'boost::constrained_types::bounds_specifiers' namespace, so maybe there's no need to add '_bounds' to each name at the end:
bounds_specifiers::integral_bounds -> bounds_specifiers::integral bounds_specifiers::generated_bounds -> bounds_specifiers::generated bounds_specifiers::static_bounds -> bounds_specifiers::static
Makes sense.
- OTOH, the bounded policies' names seem to be to short and not properly chosen, I'd change their names so they say what the policy does when an attempt is made to assign an out-of-bounds value:
bounded_policies::error -> bounded_policies::failing bounded_policies::wrap -> bounded_policies::wrapping bounded_policies::clip -> bounded_policies::clipping
Probably better...
- maybe changing the namespaces' names from plural to singular would make the names of policies more meaningful:
error_policies::throw_exception -> error_policy::throw_exception bounded_policies::error -> bounded_policy::failing bounds_specifiers::static_bounds -> bounds_specifier::static
I prefer the plural. Jeff

| -----Original Message----- | From: boost-bounces@lists.boost.org | [mailto:boost-bounces@lists.boost.org] On Behalf Of Robert Kawulak | Sent: 05 October 2005 10:33 | To: boost@lists.boost.org | Subject: Re: [boost] [constrained_types] Naming changes | | I'm considering some changes in naming, in particular: | | - I'd change 'constrained_type' to 'constrained', Sounds better IMO. | - I wonder if I should move 'constrained' and its aliases | ('boounded_int' | etc.) up form 'boost::constrained_types' namespace directly to 'boost' | namespace - these are things that are most likely to be used and maybe | 'boost' is better for them (or maybe, instead of moving them, using | declarations in 'boost' will suffice), Not sure. | - the bounds specifiers are in | 'boost::constrained_types::bounds_specifiers' | namespace, so maybe there's no need to add '_bounds' to each | name at the | end: | | bounds_specifiers::integral_bounds -> | bounds_specifiers::integral | bounds_specifiers::generated_bounds -> | bounds_specifiers::generated | bounds_specifiers::static_bounds -> | bounds_specifiers::static Yes, _bounds doesn't add anything. Does the _specifiers add much? bounds::integral bounds::generated bounds::fixed | - OTOH, the bounded policies' names seem to be to short and | not properly | chosen, I'd change their names so they say what the policy | does when an | attempt is made to assign an out-of-bounds value: | | bounded_policies::error -> bounded_policies::failing | bounded_policies::wrap -> bounded_policies::wrapping | bounded_policies::clip -> bounded_policies::clipping I think the shorter is still clear - at least it isn't abbreviated. | - maybe changing the namespaces' names from plural to | singular would make | the names of policies more meaningful: | | error_policies::throw_exception -> | error_policy::throw_exception | bounded_policies::error -> | bounded_policy::failing Yes singular is much better. | bounds_specifiers::static_bounds -> bounds_specifier::static As you noted static is forbidden. local_static is a bit long? bounds::fixed perhaps??? I shouldn't get too concerned about the names for now. They are fairly easy to change with global edits, even in the documentation. You might like to consider your code could be used by the date_time library (which already uses constrained types) and perhaps elsewhere in existing Boost libraries. Ease of plug-in will be a major 'selling' point. And of course documentation including many examples is VERY important. Looking good to me but I haven't looked in detail or used it in anger yet. Paul Paul A Bristow Prizet Farmhouse, Kendal, Cumbria UK LA8 8AB +44 1539 561830 +44 7714 330204 mailto: pbristow@hetp.u-net.com www.hetp.u-net.com

From: "Paul A Bristow" <pbristow@hetp.u-net.com> | From: boost-bounces@lists.boost.org
| [mailto:boost-bounces@lists.boost.org] On Behalf Of Robert Kawulak | | I'm considering some changes in naming, in particular: | | - I'd change 'constrained_type' to 'constrained',
Sounds better IMO.
Agreed, but what is the corresponding namespace name, "constraineds?" I wonder if constrained_types::constrained would be acceptable?
| - I wonder if I should move 'constrained' and its aliases | ('boounded_int' | etc.) up form 'boost::constrained_types' namespace directly to 'boost' | namespace - these are things that are most likely to be used and maybe | 'boost' is better for them (or maybe, instead of moving them, using | declarations in 'boost' will suffice),
Not sure.
They should not be in the boost namespace. Using directives, declarations, and aliases can be used when desired. We don't want to add more to the boost namespace than necessary. Besides, if you later find that it is desirable, you only need this: namespace boost { using ::boost::constrained_types::constrained; }
| bounds_specifiers::integral_bounds -> | bounds_specifiers::integral | bounds_specifiers::generated_bounds -> | bounds_specifiers::generated | bounds_specifiers::static_bounds -> | bounds_specifiers::static
Yes, _bounds doesn't add anything. Does the _specifiers add much?
bounds::integral bounds::generated bounds::fixed
Much better.
| - OTOH, the bounded policies' names seem to be to short and | not properly | chosen, I'd change their names so they say what the policy | does when an | attempt is made to assign an out-of-bounds value: | | bounded_policies::error -> bounded_policies::failing | bounded_policies::wrap -> bounded_policies::wrapping | bounded_policies::clip -> bounded_policies::clipping
I think the shorter is still clear - at least it isn't abbreviated.
| - maybe changing the namespaces' names from plural to | singular would make | the names of policies more meaningful: | | error_policies::throw_exception -> | error_policy::throw_exception | bounded_policies::error -> | bounded_policy::failing
Yes singular is much better.
How about eliminating the separate namespace? constrained_types::error constrained_types::wrap constrained_types::clip In use, those would look like this: typedef constrained_type<error<bounds::integral... typedef constrained_type<wrap<bounds::integral... typedef constrained_type<clip<bounds::integral... The first one doesn't look right to me as it somehow suggests that the type is an error type (or is wrong!). How about this variation: typedef constrained_type<error_at_boundaries<bounds::integral... typedef constrained_type<wrap_at_boundaries<bounds::integral... typedef constrained_type<clip_at_boundaries<bounds::integral... Those are a bit verbose, but are possibly clearer. Both of those are odd when you still have bounds::*. Maybe this would work: typedef constrained_type<constraint_handling::error<bounds::... typedef constrained_type<constraint_handling::wrap<bounds::... typedef constrained_type<constraint_handling::clip<bounds::...
| bounds_specifiers::static_bounds -> bounds_specifier::static
As you noted static is forbidden. local_static is a bit long?
bounds::fixed
perhaps???
I like it. It's easy enough to document that the limits are/must be compile time constants. -- Rob Stewart stewart@sig.com Software Engineer http://www.sig.com Susquehanna International Group, LLP using std::disclaimer;

Robert, I just started playing with your latest post, I think it looks great. "Robert Kawulak" <kawulak@student.agh.edu.pl> wrote in message news:!~!UENERkVCMDkAAQACAAAAAAAAAAAAAAAAABgAAAAAAAAAg4xUPOJl6UarljpIQw8sgsKAAAAQAAAAwtAEchQLvEKDIrUuhiOmSgEAAAAA@student.agh.edu.pl...
Hi,
The new, almost finished constrained_types library is here: http://student.agh.edu.pl/~kawulak/ct.zip. It's later than I promised, but recently I didn't have much time and I just wanted to polish it before publishing. I successfully compiled it with the following compilers: gcc 4.0.0 (Djgpp) gcc 3.4.2 (MinGW) Borland C++ 5.6.4 Microsoft C++ 13.10.3077 Digital Mars 8.45c
From: Paul A Bristow | > If you call it the "Constrained Types" library, and use the | > namespace "constrained_types," does "constrained" for the type | > name fit with Boost prior art and intention? Those names sound a | > lot better, so that may be sufficient justification, but I don't | > want to presume this approach is acceptable to Boost as a whole. | | For me the latters also sound better, what do you people think?
I think these short, unabbreviated but accurate names sound good, and fit with established names.
I didn't change the name of constrained_type template to constrained yet, but if this shorter form is OK then I'll do this before next update.
Also I am sure I am not alone in being encouraged by the progress so far - but Boost needs this to be _FINISHED_ including the documentation (including acknowledgement to the several previous but not quite finished contributions, and rationale), tests and EXAMPLES of use.
I'm still working on it :) Currently I'm working on better tests and examples, but for now included test.cpp must suffice. Documentation so far is only in the form of code comments, I'll take care of this later.
From: Larry Evans
Just uploaded to http://www.boost-consulting.com/vault in the Template Metaprogramming directory in range_all.zip.
I looked into the code, but I must say I'm far from being an mpl expert and I had difficulties with understanding the code ;-) Maybe you could look into my code and figure out if it could be reused?
As to the function-local static objects - I've created another bounds specifier class which doesn't create any statics and made it the default, the static version is still available though.
And another thing, which is quite important and many people may ask about this - why bounded_int and the like doesn't take only MinValue and MaxValue parameters and deduce the underlying type to be the smallest type that can hold both the values? At first I also thought it's a very good idea, I even implemented integral_bounds wrapper for autoamtic type selection. But then I came to conclusion that automatic type selection can more harm than help.
Consider such situation: let's assume that unsigned char's range is <0, 255> and you want to create bounded_int<0, 255>. What underlying type would be used? That would be unsigned char. That's great, this is what we wanted - no space is wasted, the automatic type selection has chosen the most appropriate type. But this bounded type is useless for any operations other than incrementing/decrementing! If we try to assign any out-of-bounds value, it'll be truncated to unsigned char before assignment, and the assigned temporary will of course lay within bounds - from the point of view of bounded_int everything's OK.
To avoid the problem of overflows, we could select some type larger than unsigned char, on which one can perform the wanted operations without overflows. But how much larger? It depends on the operations one's going to perform. But howcome the auto type selection mechanism is supposed to know how much is "enough" for us? It can't, and therefore I think that type selection should be a conscious decision of a programmer, not left to any magical wizard. Making the automatic type selection mechanism select a type at least twice as big as needed could be a solution. This way we can protect ourselves against overflows in most situations. But unfortunately not all, and so I'm also afraid that using such mechanism could be a bad idea because a programmer who uses it, assuming it's safe in "most situations", could forget about situations in which it's not and write code which does contain overflows.
The best (and only, I think) way to avoid any overflows is to use some unlimited range integer class as the underlying type (like ::std::N1744::integer or mentioned somewhere big_int). A little worse solution, that doesn't allow to avoid overflows, but at least signals them by throwing an exception, is to use a safe integer class (similar to safe_int described at http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dncode/html /secure01142004.asp). The problem with these solutions is that they both aren't available in Standard C++ nor in Boost yet.
Best regards, Robert
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

Hi,
From: Dan McLeran
Robert,
I just started playing with your latest post, I think it looks great.
Thanks, it's nice to hear (read) it! :) If you've written some pieces of code which would be useful as examples or test programs, then maybe you'd send them to me? I'm currently working on it and it might be useful. (BTW I'll be back at Sunday, 'till then I won't be able to response to any posts.) Thanks, Robert

Hi all, I've got the following "moral dilemma": there's an easy way to let the constrained type have dynamic bounds when needed. I.e. with the current policies nothing changes, but also a new bounds-specifying policy could be added that lets change the bounds at run-time. The trick is that the policies would have to be inherited by the constrained_type template. And here the problem begins - with some compilers inheriting from classes with no members doesn't change the sizeof of object, while with others it does. For instance: struct e { }; struct f : public e { }; // A class inherited from empty base classes, with a char member struct g : public f { char c; }; // Same as g but not inherited struct h { char c; }; The sizeof for e, f, g and h is, respectively: with gcc & MSVC: 1, 1, 1, 1 DMC: 1, 1, 2, 1 Borland: 8, 8, 16, 1 So the point is that when the policies are inherited, then users may have to pay for this with extra size of constrained objects, even when the policy classes doesn't contain any non-static members (which is the case with the current policies). Is there any workaround for this (IOW is there any way to make inheritance of empty classes not make sizeof grow)? Of course composition instead of inheritance is a no-go, because it always makes sizeof bigger. Is it worth to add this functionality to the constrained type even though with some compilers its size will grow? Robert

On 10/12/2005 10:52 AM, Robert Kawulak wrote: [snip]
current policies). Is there any workaround for this (IOW is there any way to make inheritance of empty classes not make sizeof grow)? Of course composition instead of inheritance is a no-go, because it always makes
By "composition" (of f, for example) do you mean: // A class inherited from empty base classes, with a char member struct g { f a_f; char c; }; ?
sizeof bigger. Is it worth to add this functionality to the constrained type even though with some compilers its size will grow?
The policy_ptr library in sandbox used to have something that could test whether a base class was empty and eliminate it from the inheritance. I think the template class used was already somewhere in boost. Looking... Yes. A copy is at: http://cvs.sourceforge.net/viewcvs.py/boost-sandbox/boost-sandbox/boost/mana... HTH.

From: Larry Evans
By "composition" (of f, for example) do you mean:
// A class inherited from empty base classes, with a char member struct g { f a_f; char c; };
?
Yes.
The policy_ptr library in sandbox used to have something that could test whether a base class was empty and eliminate it from the inheritance. I think the template class used was already somewhere in boost. Looking...
Yes. A copy is at:
http://cvs.sourceforge.net/viewcvs.py/boost-sandbox/boost-sand box/boost/managed_ptr/optimally_inherit.hpp
But this is only about multiple inheritance, right? I use single inheritance, so this seems not to be useful in the case...

On 10/12/2005 01:24 PM, Robert Kawulak wrote:
From: Larry Evans [snip] But this is only about multiple inheritance, right? I use single
Hmm... I don't know. I'd have to look closer. David Held would obviously know right away.
inheritance, so this seems not to be useful in the case...
OOPS. Sorry if that's so.

From: "Robert Kawulak" <kawulak@student.agh.edu.pl>
here the problem begins - with some compilers inheriting from classes with no members doesn't change the sizeof of object, while with others it does. For instance:
struct e { };
struct f : public e { };
// A class inherited from empty base classes, with a char member struct g : public f { char c; };
// Same as g but not inherited struct h { char c; };
The sizeof for e, f, g and h is, respectively: with gcc & MSVC: 1, 1, 1, 1 DMC: 1, 1, 2, 1 Borland: 8, 8, 16, 1
You should assume a quality compiler that provides the EBO for the general case. For Borland, you can reduce the problem by conditionally inserting a char (not bool!) data member in the policies. -- Rob Stewart stewart@sig.com Software Engineer http://www.sig.com Susquehanna International Group, LLP using std::disclaimer;

On 10/3/05, Robert Kawulak <kawulak@student.agh.edu.pl> wrote:
Hi,
The new, almost finished constrained_types library is here: http://student.agh.edu.pl/~kawulak/ct.zip. It's later than I promised, but recently I didn't have much time and I just wanted to polish it before publishing. I successfully compiled it with the following compilers:
<snip> It would perhaps be a good idea to use mpl::int_<> instead of give_number<> to specify a constraint limit. You can also use mpl::math::double_c<> (available from the file vault: Template Metaprogramming/mpl_math.zip) Example: ct::bounded< double, boost::mpl::math::string_to_double<0,'.',1>, boost::mpl::int_<1> >::type d_0_1__1; To extract a runtime equivalent: boost::mpl::runtime_value<MinValGen::value_type>(MinValGen()); Regards, Peder
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

Hi,
From: Peder Holt
It would perhaps be a good idea to use mpl::int_<> instead of give_number<> to specify a constraint limit.
But the point is that give_number is a function object type, it can't be replaced with a template metafunction. If one wants to have integral bounds, he may use bounded_int which takes integral constants as its parameters.
You can also use mpl::math::double_c<> (available from the file vault: Template Metaprogramming/mpl_math.zip)
The problem is double_c is not a function object type - it only defines operator value_type(). If it'd also define value_type operator() () { return static_cast<value_type>(*this); } then it would be usable in this case. Maybe you'll consider the possibility to add this operator to double_c?
To extract a runtime equivalent: boost::mpl::runtime_value<MinValGen::value_type>(MinValGen());
There's something I don't understand - what does the above line do? I can't see runtime_value having a constructor? Best regards, Robert

On 10/14/05, Robert Kawulak <kawulak@student.agh.edu.pl> wrote:
Hi,
From: Peder Holt
It would perhaps be a good idea to use mpl::int_<> instead of give_number<> to specify a constraint limit.
But the point is that give_number is a function object type, it can't be replaced with a template metafunction. If one wants to have integral bounds, he may use bounded_int which takes integral constants as its parameters.
You can also use mpl::math::double_c<> (available from the file vault: Template Metaprogramming/mpl_math.zip)
The problem is double_c is not a function object type - it only defines operator value_type(). If it'd also define
value_type operator() () { return static_cast<value_type>(*this); }
The mpl numerical holder classes already define a conversion operator, converting the held number to some native type defined by value_type. Would it not be possible to modify your library to use the conversion operator in stead? I don't think modifying mpl for this is a good idea...
then it would be usable in this case. Maybe you'll consider the possibility to add this operator to double_c?
To extract a runtime equivalent: boost::mpl::runtime_value<MinValGen::value_type>(MinValGen());
There's something I don't understand - what does the above line do? I can't see runtime_value having a constructor?
Sorry. Typo. Should be: boost::mpl::runtime_value<MinValGen::value_type>()(MinValGen()); Basically the same as: MinValGen::value_type(MinValGen()), except not all the types in mpl::math has a conversion operator (yet...) Regards, Peder
Best regards, Robert
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

Hi,
From: Peder Holt
The problem is double_c is not a function object type - it only defines operator value_type(). If it'd also define
value_type operator() () { return static_cast<value_type>(*this); }
The mpl numerical holder classes already define a conversion operator, converting the held number to some native type defined by value_type. Would it not be possible to modify your library to use the conversion operator in stead?
Actually, after thinking the problem over, I've came to a conclusion that it's not that bad idea :) I'll try to implement this, I think it may simplify some things.
To extract a runtime equivalent: boost::mpl::runtime_value<MinValGen::value_type>(MinValGen());
There's something I don't understand - what does the above line do? I can't see runtime_value having a constructor?
Sorry. Typo. Should be: boost::mpl::runtime_value<MinValGen::value_type>()(MinValGen());
Basically the same as: MinValGen::value_type(MinValGen()), except not all the types in mpl::math has a conversion operator (yet...)
Thanks for explanation. But could you tell what is runtime_value used for? Best regards, Robert

On 10/18/05, Robert Kawulak <kawulak@student.agh.edu.pl> wrote:
Hi,
From: Peder Holt
The problem is double_c is not a function object type - it only defines operator value_type(). If it'd also define
value_type operator() () { return static_cast<value_type>(*this); }
The mpl numerical holder classes already define a conversion operator, converting the held number to some native type defined by value_type. Would it not be possible to modify your library to use the conversion operator in stead?
Actually, after thinking the problem over, I've came to a conclusion that it's not that bad idea :) I'll try to implement this, I think it may simplify some things.
To extract a runtime equivalent: boost::mpl::runtime_value<MinValGen::value_type>(MinValGen());
There's something I don't understand - what does the above line do? I can't see runtime_value having a constructor?
Sorry. Typo. Should be: boost::mpl::runtime_value<MinValGen::value_type>()(MinValGen());
Basically the same as: MinValGen::value_type(MinValGen()), except not all the types in mpl::math has a conversion operator (yet...)
Thanks for explanation. But could you tell what is runtime_value used for?
Some "numerical holder" classes (such as rational) have a rather complex function for extracting a runtime value. The functionality has therefore been moved to the meta-function runtime_value instead. The interface for mpl::math is still very dynamic, so it may be that this construct will disappear in the future. Regards, Peder
Best regards, Robert
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

From: Simon Buchan <simon@hand-multimedia.co.nz>
Robert Kawulak wrote:
In bounded policies I use passed_value_type initialize() where passed_value_type is value_type for integral types and const value_type & for other types. The second returns a reference to a static object - that's the most efficient method I can think of, initialization takes only one copy-construction (for details please look into the code).
ref to static? It feels cludgy. Just trust the RVO even for user classes, IMHO, it's how the std lib works. Unfortunately the RVO can't get rid of the side-effects of c/d'tors, so you should make sure it's documented that values must have normal copy semantics if default initialisation is used.
I agree. Returning a reference to a function local static is kludgy.
What you are suggesting is equivalent to suggesting that std::vector should be named "vector_type" because it is a class template.
Uhh, maybe you're right ;-) I don't know why, but it just "byte my eyes" when I see a type named "something_value"... Nevermind, if people here really resist that it should be called constrained_value instead of constrained_type, then OK - I'll change it.
Why not just 'constrained'? ie. constrained<int>?
That works for me. -- Rob Stewart stewart@sig.com Software Engineer http://www.sig.com Susquehanna International Group, LLP using std::disclaimer;

From: "Robert Kawulak" <kawulak@student.agh.edu.pl> Please don't snip attributions.
Use
void initialize(value_type & value_o);
rather than
value_type initialize();
Thus, when passed the data member to initialize, it can initialize that object directly. Granted, (N)RVO can often avoid the copy, but this change will ensure you get the efficiency.
I don't think so, because your version of initialize couldn't be used to initialize a value in constructor's initialization list. So first the value would be default-constructed, and then assigned another value using initialize.
Ah. If you're using it in an initializer list, then your version is better. (N)RVO is your friend in that case. -- Rob Stewart stewart@sig.com Software Engineer http://www.sig.com Susquehanna International Group, LLP using std::disclaimer;

On 9/25/05 7:02 PM, "Robert Kawulak" <kawulak@student.agh.edu.pl> wrote:
Restricted is ok, but I like constrained better. Please see:
http://www.boost.org/doc/html/constrained_value.html http://www.boost.org/boost/date_time/constrained_value.hpp http://www.artima.com/weblogs/viewpost.jsp?thread=79470
Jeff [SNIP] BTW, constrained_value of Christofer Diggins has at least one 'bug' - it has a default constructor which default-initialises the value, and doesn't check if this default value conforms to the constraints. I also believe, that it'd be better to supply operator const value() than operator value() - this conversion is implicit so the const version would be safer.
Why bother with the "const"? The usage will already return a r-value, i.e. a temporary. The kinds of mutable operations that can be done on it are already restricted. The only times I've seen mutable operations on such values are ones that were deliberately done. The "const" adds nothing but annoyance; the safety-conscious won't need it since they wouldn't try mutable code, and the programmers that want to abuse a mutable operation would be upset that you locked them out. It's the same kind of controversy about (member) functions returning non-reference objects with "const" attached. (And we seen "cute" tricks in C++ made for our "benefit" back-fire later, like std::vector<bool>.) -- Daryle Walker Mac, Internet, and Video Game Junkie darylew AT hotmail DOT com

Hi,
I also believe, that it'd be better to supply operator const value() than operator value() - this conversion is implicit so the const version would be safer.
Why bother with the "const"? The usage will already return a r-value, i.e. a temporary. The kinds of mutable operations that can be done on it are already restricted. The only times I've seen mutable operations on such values are ones that were deliberately done. The "const" adds nothing but annoyance; the safety-conscious won't need it since they wouldn't try mutable code, and the programmers that want to abuse a mutable operation would be upset that you locked them out. It's the same kind of controversy about (member) functions returning non-reference objects with "const" attached. (And we seen "cute" tricks in C++ made for our "benefit" back-fire later, like std::vector<bool>.)
-- Daryle Walker
Probably you're right, I wasn't thinking it over very much because in the current implementation I'm working on the conversion operator returns const value_type & (because it must also support UDTs, that might be inefficient to return by value) so there's no question whether const is needed or not, it must be there. The reason I was thinking so was "Exceptional C++" item 20 p.9 which says that postincrement operator should return a const value, from this I deduced that conversion operator should also. But as I mentioned, I didn't think of it a lot so I may be wrong ;-). Best regards, Robert

On 9/26/05 6:16 AM, "Robert Kawulak" <kawulak@student.agh.edu.pl> wrote:
The reason I was thinking so was "Exceptional C++" item 20 p.9 which says that postincrement operator should return a const value, from this I deduced that conversion operator should also. But as I mentioned, I didn't think of it a lot so I may be wrong ;-).
Actually, under my opinion/theory, NO function, member function, or operator returns a const non-reference. That's includes the post-increment operator. However, I don't have the "Exceptional C++" book, so I don't know the author's reasoning for his opinion. -- Daryle Walker Mac, Internet, and Video Game Junkie darylew AT hotmail DOT com

In article <BAY104-DAV1150B74243DE0C91E6C3DDBF8C0@phx.gbl>, Daryle Walker <darylew@hotmail.com> wrote:
Actually, under my opinion/theory, NO function, member function, or operator returns a const non-reference. That's includes the post-increment operator. However, I don't have the "Exceptional C++" book, so I don't know the author's reasoning for his opinion.
Implement a post-increment that returns a non-const, then see what x++++ does, and you'll understand the reasoning :-) hth Ben -- I changed my name: <http://periodic-kingdom.org/People/NameChange.php>

Hi,
From: Ben Artin
In article <BAY104-DAV1150B74243DE0C91E6C3DDBF8C0@phx.gbl>, Daryle Walker <darylew@hotmail.com> wrote:
Actually, under my opinion/theory, NO function, member function, or operator returns a const non-reference. That's includes the post-increment operator. However, I don't have the "Exceptional C++" book, so I don't know the author's reasoning for his opinion.
Implement a post-increment that returns a non-const, then see what x++++ does, and you'll understand the reasoning :-)
This is the reasoning shown in "Exceptional C++" - the point is that UDTs' behaviour should be similar to built-in types whenever possible. You can't do x++++ with int, so you shouldn't be able to do this with UDTs either. Recently I found another good reason to return const value - bounds-specifier policy class contains two functions: min_value() and max_value(). These values are constant by nature (they don't change during execution of a program), so it's natural to return them as consts. This may help finding bugs, because it's not very likely that someone would want to modify on purpose the value returned from one of these functions - would it make any sence? Best regards, Robert

"Robert Kawulak": Is it still possible to send you email directly? I get errors for last few days. /Pavel

Here is an outline of my idea for bounded integral types. I am showing only signed scalar integer. The library should also have unsigned, and also support complex integral types, in my opinion. The latter may be more controversial.

I'm very impressed by Robert Kawulak's contrained_types. I'm mostly interested in contrained integral types. constrained_types appears to concentrate on types whose bounds are specified at compile time (integral constant template parameters). I'm more interested in bound specified at runtime. I believe (without proof) that for many applications there will be little performance difference. I say this because I'm expecting in many (most?) cases the actual integral values will be known to the compiler. Has any thought been given to adding this? Or, perhaps even making this the default bounded_int, (wrapping_int, etc.) type?

Hi,
From: Neal Becker <...> I'm more interested in bound specified at runtime. I believe (without proof) that for many applications there will be little performance difference. I say this because I'm expecting in many (most?) cases the actual integral values will be known to the compiler.
Has any thought been given to adding this? Or, perhaps even making this the default bounded_int, (wrapping_int, etc.) type?
Yes, I'm still thinking about this. The difference between static and run-time bounds is that in the latter case a bounded object needs to store the bounds which makes its size at least 3 times bigger. Another one is that with static bounds many checking operations may be optimised-away or at least inlined. Therefore I'd rather not make run-time bounds the default. I'm working on this as an optional feature, but this is a little bit harder than it seems to unite the two concepts. Best regards, Robert

Robert Kawulak wrote:
Hi,
From: Neal Becker <...> I'm more interested in bound specified at runtime. I believe (without proof) that for many applications there will be little performance difference. I say this because I'm expecting in many (most?) cases the actual integral values will be known to the compiler.
Has any thought been given to adding this? Or, perhaps even making this the default bounded_int, (wrapping_int, etc.) type?
Yes, I'm still thinking about this. The difference between static and run-time bounds is that in the latter case a bounded object needs to store the bounds which makes its size at least 3 times bigger. Another one is that with static bounds many checking operations may be optimised-away or at least inlined. Therefore I'd rather not make run-time bounds the default. I'm working on this as an optional feature, but this is a little bit harder than it seems to unite the two concepts.
Yes, the advantage of integral template parameter bounds is primarily that it could be optimized or inlined - but I think the same is true if the bound checking function is inline and the bounds are known at compile time. IIUC, integral template parameter has the advantage that it might be optimized, but the disadvantage is less flexibility. A static bounds checking function could also be inlined and optimized away in case the bounds are known at compile time - this same condition is the only time the template parameter could be used at all. Therefore, I expect there is no performance advantage to the integral template parameter approach, but less flexibility. I'm thinking something like this: template<typename checker_t> class bounded {... bounded (checker_t check) ... assign () { check (value); } checker_t is a functor which could store the bounds. I'm guessing it could allow checking to be inlined. I guessing the size of a bounded object would not necessarily be increased. For example, suppose we _did_ know the bounds at compile time. Then checker_t could be wrap<0,10>.

From: Neal Becker
I'm thinking something like this:
template<typename checker_t> class bounded {... bounded (checker_t check) ...
assign () { check (value); }
This is quite similar to what I was going to implement.
allow checking to be inlined. I guessing the size of a bounded object would not necessarily be increased.
If you store checker as a member then the size would certainly be increased even if checker_t is empty. I'm going to use boost::compressed_pair<value_type, checker_t> to avoid this. I could privately inherit from checker_t instead, but I want the value_type member sub-object to be the first in the object to optimise access to it. Best regards, Robert

On Thu, 20 Oct 2005 23:09:58 +0200, Robert Kawulak wrote
Hi,
From: Neal Becker <...> I'm more interested in bound specified at runtime. I believe (without proof) that for many applications there will be little performance difference. I say this because I'm expecting in many (most?) cases the actual integral values will be known to the compiler.
Has any thought been given to adding this? Or, perhaps even making this the default bounded_int, (wrapping_int, etc.) type?
Yes, I'm still thinking about this. The difference between static and run-time bounds is that in the latter case a bounded object needs to store the bounds which makes its size at least 3 times bigger. Another one is that with static bounds many checking operations may be optimised-away or at least inlined. Therefore I'd rather not make run-time bounds the default. I'm working on this as an optional feature, but this is a little bit harder than it seems to unite the two concepts.
Catching up with really old email... I'll just say that for my money I *only* care about compile time types. The extra storage Robert cites for an application like date-time is unacceptable. I'll also state that I believe there will be a performance hit as well on construction of the type (probably 3 integer copies instead of 1 in the constructor). I'll try to find some time to look over the latest implementation soon.... Jeff

From: Jeff Garland
I'll just say that for my money I *only* care about compile time types. The extra storage Robert cites for an application like date-time is unacceptable. I'll also state that I believe there will be a performance hit as well on construction of the type (probably 3 integer copies instead of 1 in the constructor).
This is why I'm trying to introduce run-time bounds in such a way that they will cause no negative effects in case of using compile-time bounds. I think I've already got a solution, I just need to implement it.
I'll try to find some time to look over the latest implementation soon....
There were some important changes since the last published implementation, I'll send the new one as soon as it's ready (I hope it to happen in this week). Best regards, Robert
participants (14)
-
Ben Artin
-
christopher diggins
-
Dan McLeran
-
Daryle Walker
-
Jeff Garland
-
Larry Evans
-
Neal Becker
-
Paul A Bristow
-
Pavel Vozenilek
-
Peder Holt
-
Rob Stewart
-
Robert Kawulak
-
Robert Kawulak
-
Simon Buchan