Boost logo

Boost :

Subject: [boost] [constrained-value] Some observations and questions.
From: Jeroen N. Witmond [Bahco] (jnw_at_[hidden])
Date: 2009-01-15 14:41:30


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

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.



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]
[ 2]
[ 3]
[ 4] file libs/constrained_value/doc/src/examples.cpp in [3].
[ 5]
[ 6]
[ 7]
[ 8] file boost/constrained_value/unconstrained.hpp in [3].
[ 9]

Boost list run by bdawes at, gregod at, cpdaniel at, john at