[constrained-value] Some observations and questions.

Greetings, Please forgive me for intruding on the Boost Development mailing list. I'm rather new to Boost, but I'm in love with it, because IMHO it shows C++ as it should be used. :) While browsing this mailing list, I came across the review announcement[1] for the Boost Constrained Value library[2]. I like the concept, so I downloaded[3] and installed the library. I also installed file boost/utility/swap.hpp from the sandbox. I had to hack the example program[4] to get around "[boost] [utility/swap] Ambiguous overload"[5]. To get familiar with Boost and the Boost Constrained Value library, I first rewrote the example program into a Boost.Test testcase[6]. (I have tried not to disturb the documentation generated from this file, but I did not test this.) As testcase, it runs succesfully, with the hack mentioned above. (At least for me, Emacs has problems with font-lock-mode[7] on this file. The original example program does not demonstrate this problem.) In the section on Custom error policies in the example program, perhaps it should be explicitely stated that: - on entry into the error handler, constraint(new_value) will always be false. An error handler that neither changes the constraint, nor supplies a valid value can therefore throw unconditionally. - on entry into the error handler, constraint(value) will only be false during the construction of an object with an invalid value. If the error handler does not throw in this case, the library will raise signal SIGABRT (application abort requested). - the only case where the error handler can be empty is when the constraint always returns true, as in 'template <typename ValueType> class unconstrained'[8]. This code[9] illustrates these points. Next I was itching to create and more real-life use case for the Boost Constrained Value library, with special attention on improving error reporting. So I wrote four template classes[10], implementing non-positive, non-negative, positive and negative constraints over any integral type. (This code still can be improved in many ways.) These constrained integers can be declared like: positiveInteger<int> i; // Construction with value 0 would fail, BOOST_CHECK_EQUAL( i, 1 ); // so it is set to 1. They can used like teir base type. In case of constraint violations (e.g. 'i = 1;' for 'i' above), an exception is thrown, which derives from both std::logic_error and boost::exception. The std::logic_error::what() returns: Failed assert(1 <= 0); And from the boost::exception, the following information can be retrieved (slightly edited to fit the newsgroup): constrained-integer.hpp:168: In '[very long function name]': Failed assert(-1 > 0); constrained-integer.cpp:82: Constraint was defined here. See the first testcase in the Boost.Test testsuite[11] for the code that produced these messages from boost::exception. The remainder of the testsuite runs the four template classes both against fundamental types, and against classes that implement infinite precision integer arithmetic. This showed that I needed to implement 'bool operator == (const Integer & v) const' for these classes, but not for the fundamental types. As implementing this operator==() for fundamental types results in compiler errors, the implementation is present only when preprocessor symbol 'CLASS_TYPE' is defined. (My attempt to hack this in the Boost Constrained Value library source failed.) Note that no hackery is needed for the relational operators used in the constraints. Otherwise, the testsuite compiles correctly and runs almost as expected. It would appear that in the process I may have discovered a bug[12] in the mp_math library in the sandbox. One question I have is related to the requirement of the Constrained Value library that the constraint and error handler objects must be completely constructed before the constrained object is constructed. In these four template classes, I handle this by deriving my template type (e.g. nonPositiveInteger) from the constraint class and indirectly from the error handler class. The purpose is to allow these template types to be used as drop-in replacements for the types they constrain. In this context it appears to work, but I'm having second thoughts about its validity and advisability. Although it is not a Boost question, is there anybody who wants to comment? One thing that has gotten me completely stumped is deriving my own template class from constrained_value::unconstrained. Whatever I try, I get the weirdest of compiler error messages. See the bottom of [10] and [11] for my latest attempt in the section guarded by '#ifdef DO_UNCONSTRAINED'. I must be missing something obvious. Also all other comments will be appreciated. Regards, Jeroen. PS: All files referenced in this email and authored by me are released under the Boost Software License, Version 1.0[99]. Note however that this code is not of release quality. [ 1] http://lists.boost.org/Archives/boost/2008/12/145581.php [ 2] http://student.agh.edu.pl/~kawulak/constrained_value/index.html [ 3] http://rk.go.pl/f/constrained_value.zip [ 4] file libs/constrained_value/doc/src/examples.cpp in [3]. [ 5] http://lists.boost.org/Archives/boost/2007/10/128494.php [ 6] http://www.xs4all.nl/~jnw/boost/constrained-value/test-constrained-value.cpp [ 7] http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=510475 [ 8] file boost/constrained_value/unconstrained.hpp in [3]. [ 9] http://www.xs4all.nl/~jnw/boost/constrained-value/understanding-ignore.cpp [10] http://www.xs4all.nl/~jnw/boost/constrained-value/constrained-integer.hpp [11] http://www.xs4all.nl/~jnw/boost/constrained-value/constrained-integer.cpp [12] http://lists.boost.org/boost-users/2009/01/43824.php [99] http://www.boost.org/LICENSE_1_0.txt

Hi,
From: Jeroen N. Witmond [Bahco]
The examples should work fine with swap.hpp taken from trunk - I haven't tried them with the sandbox version, but I guess it is an older one.
In the section on Custom error policies in the example program, perhaps it should be explicitely stated that:
[snip policy contracts] Interfaces and semantics of the policies are described here http://tinyurl.com/5wnfpj in the Parameters section. I will also add a section about the policies in the documentation, as suggested by Stjepan Rajko.
So I wrote four template classes[10] [...] They can used like teir base type.
Not exactly. The problem with inheriting from constrained is that the resulting class is no longer implicitly convertible to the underlying type. This makes it incompatible with the underlying type in even more situations than constrained is.
unconstrained is a template alias for constrained, so you should write unconstrained<xxx>::type. Best regards, Robert
participants (2)
-
Jeroen N. Witmond [Bahco]
-
Robert Kawulak