[boost][boost-users][ICL] ICL Compilation errors. Ticket #5207
Hi John, lists, I am replying to your ticket #5207 on the lists because I am afraid that you walked into a trap that others can fall into as well. In the ITL, the precursor of Boost.ICL there was a single polymorphic interval class template: itl::interval. Due to input from the list during the review I split up this "one size fit's all" template in smaller classes according to static and dynamic interval concepts. In order to help ITL users to have a simple transition from ITL to ICL I wrote a template icl::interval. icl::interval is a meta function that yields the right interval type dependent on the instance type e.g. : BOOST_STATIC_ASSERT(( boost::is_same< interval<int>::type , discrete_interval<int> >::value )); So ITL users could move from ITL to ICL just by appending a '::type' to all occurrences of 'interval<T>' So please note that interval<myType> myInterval; can not be used as an interval type in ICL functions. Please use interval<myType>::type myInterval; or one of the specific interval types discrete_interval, continuous_interval, (dynamic borders) closed_interval, right_open_interval, left_open_interval, open_interval (static borders) e.g. discrete_interval<int> myInterval; See examples http://www.joachim-faulhaber.de/boost_icl/doc/libs/icl/doc/html/boost_icl/ex... http://www.joachim-faulhaber.de/boost_icl/doc/libs/icl/doc/html/boost_icl/ex... http://www.joachim-faulhaber.de/boost_icl/doc/libs/icl/doc/html/boost_icl/ex... and docs http://www.joachim-faulhaber.de/boost_icl/doc/libs/icl/doc/html/boost_icl/in... for more detail. This reduces John's non compilable ICL statements in the following way: BOOST_AUTO_TEST_CASE(ticket_5207) { icl::interval< int >::type int_interval; icl::interval_set< int > int_set; icl::interval_map< int, int > int_map; icl::interval_map< int, int >::element_type int_element; icl::interval_map< int, int >::segment_type int_segment; // The next 4 lines compile icl::lower( int_interval ); icl::upper( int_interval ); icl::first( int_interval ); icl::last( int_interval ); // The next 4 lines are *not* supposed to compile // according to the docs: icl::add( int_set, int_set ); icl::add( int_map, int_map ); icl::subtract( int_set, int_set ); icl::subtract( int_map, int_map ); int_set += int_interval; // compiles // Here you are right, John: // The next 4 lines should compile according // to the docs, but don't icl::disjoint( int_map, int_element ); icl::disjoint( int_map, int_segment ); icl::intersects( int_map, int_segment ); icl::intersects( int_map, int_element ); // Those four are pretty special. I doubt anyone will // use them. But I will complete the library here. } Thanks for using my library and helping to improve it. Joachim -- Interval Container Library [Boost.Icl] http://www.joachim-faulhaber.de
2011/2/21 Joachim Faulhaber
Hi John, lists,
I am replying to your ticket #5207 on the lists because I am afraid that you walked into a trap that others can fall into as well.
[...]
So please note that
interval<myType> myInterval;
can not be used as an interval type in ICL functions.
Please use interval<myType>::type myInterval;
or one of the specific interval types
discrete_interval, continuous_interval, (dynamic borders) closed_interval, right_open_interval, left_open_interval, open_interval (static borders)
This reduces John's non compilable ICL statements in the following way:
BOOST_AUTO_TEST_CASE(ticket_5207) { [...] // Here you are right, John: // The next 4 lines should compile according // to the docs, but don't icl::disjoint( int_map, int_element ); icl::disjoint( int_map, int_segment ); icl::intersects( int_map, int_segment ); icl::intersects( int_map, int_element ); // I will complete the library here. }
DONE Regards, Joachim -- Interval Container Library [Boost.Icl] http://www.joachim-faulhaber.de
On 21/02/11 20:22, Joachim Faulhaber wrote:
Hi John, lists,
BOOST_AUTO_TEST_CASE(ticket_5207) { icl::interval< int>::type int_interval; icl::interval_set< int> int_set; icl::interval_map< int, int> int_map; icl::interval_map< int, int>::element_type int_element; icl::interval_map< int, int>::segment_type int_segment;
// The next 4 lines compile icl::lower( int_interval ); icl::upper( int_interval ); icl::first( int_interval ); icl::last( int_interval ); my mistake
// The next 4 lines are *not* supposed to compile // according to the docs: icl::add( int_set, int_set ); icl::add( int_map, int_map ); icl::subtract( int_set, int_set ); icl::subtract( int_map, int_map ); agreed
int_set += int_interval; // compiles
// Here you are right, John: // The next 4 lines should compile according // to the docs, but don't icl::disjoint( int_map, int_element ); icl::disjoint( int_map, int_segment ); icl::intersects( int_map, int_segment ); icl::intersects( int_map, int_element ); // Those four are pretty special. I doubt anyone will // use them. But I will complete the library here. }
Thanks for using my library and helping to improve it. NP, thanks for writing it!
I have started to use statically bounded intervals and am finding more
compilation issues. For example with finding elements in a map:
#define BOOST_ICL_USE_STATIC_BOUNDED_INTERVALS
#include
2011/2/22 John Reid
I have started to use statically bounded intervals and am finding more compilation issues. For example with finding elements in a map:
#define BOOST_ICL_USE_STATIC_BOUNDED_INTERVALS #include
void f() { namespace icl = ::boost::icl; icl::interval_map< float, int >().find( 0 ); }
This compiles without the #define but fails on static intervals.
This is on purpose. The reason is that we can not represent a single
element x using a right-open interval [x,?) of continuous values.
right_open_interval is the default for statically bounded intervals,
if BOOST_ICL_USE_STATIC_BOUNDED_INTERVALS is defined. In order to use
find on an interval_map we have to construct an interval that
represents a single element (internally). This is not possible in the
logic of the ICL so this code won't compile.
interval_map::find is a pretty late addition to ITL/ICL, because using
find in the STL way makes little sense on interval containers most of
the time. We can not "find" an large interval in an icl::interval_set
of small intervals.
{[0,2),[5,7)}.find([0,9))
The generalization of find is intersection. And the following function
calls compile for statically bounded right-open intervals of
continuous types:
#define BOOST_ICL_USE_STATIC_BOUNDED_INTERVALS
#include
This makes me think it might be worth having tests for every possible combination that is listed in the function synopsis for both static and for dynamic intervals: http://www.boost.org/doc/libs/1_46_0/libs/icl/doc/html/boost_icl/interface/f...
I am working on it. But as you see from this example, not every function overload works for dynamically bounded and statically bounded intervals in the same way. I think the documentation can be improved here.
I can keep you up-to-date with any further problems I find
please do.
but I'm just wondering whether it would be easier to fix them all in one go.
Currently it's no problem for me to fix them as they are detected. Cheers, Joachim -- Interval Container Library [Boost.Icl] http://www.joachim-faulhaber.de
On 22/02/11 20:03, Joachim Faulhaber wrote:
2011/2/22 John Reid
I have started to use statically bounded intervals and am finding more compilation issues. For example with finding elements in a map:
#define BOOST_ICL_USE_STATIC_BOUNDED_INTERVALS #include
void f() { namespace icl = ::boost::icl; icl::interval_map< float, int>().find( 0 ); }
This compiles without the #define but fails on static intervals.
This is on purpose. The reason is that we can not represent a single element x using a right-open interval [x,?) of continuous values. right_open_interval is the default for statically bounded intervals, if BOOST_ICL_USE_STATIC_BOUNDED_INTERVALS is defined. In order to use find on an interval_map we have to construct an interval that represents a single element (internally). This is not possible in the logic of the ICL so this code won't compile.
Nevertheless, users will expect to be able to locate elements in sets. How should they do this? Does icl::contains( icl::interval_set< int >(), 0 ); compile, but icl::contains( icl::interval_set< float >(), 0. ); does not for the same reason?
interval_map::find is a pretty late addition to ITL/ICL, because using find in the STL way makes little sense on interval containers most of the time. We can not "find" an large interval in an icl::interval_set of small intervals.
{[0,2),[5,7)}.find([0,9))
If we cannot find the large interval, isn't the end() iterator a suitable return value to suggest it was not in the set/map?
The generalization of find is intersection. And the following function calls compile for statically bounded right-open intervals of continuous types:
#define BOOST_ICL_USE_STATIC_BOUNDED_INTERVALS #include
{ icl::interval_map< float, int> iclmap; icl::interval_map< float, int> found; add_intersection(found, iclmap, right_open_interval<float>(0,1)); add_intersection(found, icl::interval_map< float, int>(), right_open_interval<float>(0,1)); found = iclmap& right_open_interval<float>(0,1); found = icl::interval_map< float, int>() & right_open_interval<float>(0,1); }
I'm interested to hear reasons why the following don't compile when using static bounds: icl::add( icl::interval_set< int >(), 0 ); icl::add( icl::interval_set< int >(), icl::interval< int >::type( 0, 1 ) ); icl::interval_set< int >() += 0; icl::interval_set< int >() += icl::interval< int >::type( 0, 1 ); icl::subtract( icl::interval_set< int >(), 0 ); icl::subtract( icl::interval_set< int >(), icl::interval< int >::type( 0, 1 ) ); icl::interval_set< int >() -= 0; icl::interval_set< int >() -= icl::interval< int >::type( 0, 1 ); icl::interval_set< int >() &= 0; icl::interval_set< int >() &= icl::interval< int >::type( 0, 1 ); icl::interval_set< int >() ^= ( icl::interval< int >::type( 0, 1 ) ); They all seem reasonable operations to me. In particular, for a discrete domain, operations like icl::interval_set< int >() += 0 make sense to me. That is the following are equivalent: icl::interval_set< int >() += 0 icl::interval_set< int >() += icl::interval< int >::type( 0, 1 ); I agree the documentation needs to be more explicit about what is permissible. On a side note, I don't understand the rationale for having static bounds configured by #define whilst other aspects of intervals are parameterised using templates. I would have liked to have both types of interval in the same compilation unit. However I guess it must be too late to change this fundamental design choice. Regards, John.
Hi John,
thanks again for all the questions. I am breaking up the long posting
into smaller portions.
(1) Representation of single elements with statically bounded intervals:
2011/2/23 John Reid
On 22/02/11 20:03, Joachim Faulhaber wrote:
2011/2/22 John Reid
I have started to use statically bounded intervals and am finding more compilation issues. For example with finding elements in a map:
#define BOOST_ICL_USE_STATIC_BOUNDED_INTERVALS #include
void f() { namespace icl = ::boost::icl; icl::interval_map< float, int>().find( 0 ); }
This compiles without the #define but fails on static intervals.
This is on purpose. The reason is that we can not represent a single element x using a right-open interval [x,?) of continuous values. right_open_interval is the default for statically bounded intervals, if BOOST_ICL_USE_STATIC_BOUNDED_INTERVALS is defined. In order to use find on an interval_map we have to construct an interval that represents a single element (internally). This is not possible in the logic of the ICL so this code won't compile.
Nevertheless, users will expect to be able to locate elements in sets. How should they do this?
they could use dynamically bounded intervals for continuous interval element types :P Moreover, if we work with floating point numbers, the code float pi = 3.14159 ... ; icl::interval_set<float> icl_float_set = ... ; icl::contains( icl_float_set, pi ); would be problematic anyway since pi can not be represented precisely. right_open_interval<float> pi_itv = interval_around_pi(); icl::contains( icl_float_set, interval_around_pi() ); // better
Does icl::contains( icl::interval_set< int >(), 0 ); compile, but icl::contains( icl::interval_set< float >(), 0. ); does not for the same reason?
yes. I have mentioned in the docs, that 'continuous_interval' is the only class template that allows to represent a singleton interval that contains only one element, an have provided a small example here: http://www.boost.org/doc/libs/1_46_0/libs/icl/doc/html/boost_icl/interface.h... Regards, Joachim -- Interval Container Library [Boost.Icl] http://www.joachim-faulhaber.de
(2) Generalization of "find" in the Set view and the STL/iterator view.
2011/2/23 John Reid
On 22/02/11 20:03, Joachim Faulhaber wrote:
2011/2/22 John Reid
interval_map::find is a pretty late addition to ITL/ICL, because using find in the STL way makes little sense on interval containers most of the time. We can not "find" an large interval in an icl::interval_set of small intervals.
{[0,2),[5,7)}.find([0,9))
If we cannot find the large interval, isn't the end() iterator a suitable return value to suggest it was not in the set/map?
This is a question of design decisions of course. On the one hand I
view intervals as Sets and also interval_set implements Set. (Capital
S for concept Set). In this view, it is unusual to ask whether a set
is found in a set, because one is not intended to be the element of
the other. I this view (the Set view) we can achieve everything we
need using predicates
contains, intersects
and functions
add_intersection, &= and & (intersection)
http://www.boost.org/doc/libs/1_46_0/libs/icl/doc/html/boost_icl/function_re...
On the other hand, but with a lower priority in my design, I am
supporting functions using iterators that are common to STL containers
and that will be expected by users.
'find' is only defined on element_types, because only element can be
"found" in sets. All functionality related to a "generalized find" in
the STL/iterator related view can be provided by the member functions
lower_bound, upper_bound and equal_range that are common to STL
interfaces of associative containers:
http://www.boost.org/doc/libs/1_46_0/libs/icl/doc/html/boost_icl/function_re...
Here is some code for clarification:
BOOST_AUTO_TEST_CASE(generalized_find)
{
typedef icl::interval_set<int>::iterator int_set_iterator;
icl::interval_set<int> int_set;
icl::interval<int>::type to_be_found(1,5);
int_set += icl::interval<int>::type(0,2);
int_set += icl::interval<int>::type(4,7);
int_set += icl::interval<int>::type(8,9);
int_set_iterator found;
found = int_set.lower_bound(to_be_found);
cout << *found << endl; // [0,2)
found = int_set.upper_bound(to_be_found);
cout << *found << endl; // [8,9)
std::pair
(3) More compilability issues
2011/2/23 John Reid
I'm interested to hear reasons why the following don't compile when using static bounds:
icl::add( icl::interval_set< int >(), 0 ); icl::add( icl::interval_set< int >(), icl::interval< int >::type( 0, 1 ) ); icl::interval_set< int >() += 0; icl::interval_set< int >() += icl::interval< int >::type( 0, 1 );
icl::subtract( icl::interval_set< int >(), 0 ); icl::subtract( icl::interval_set< int >(), icl::interval< int >::type( 0, 1 ) ); icl::interval_set< int >() -= 0; icl::interval_set< int >() -= icl::interval< int >::type( 0, 1 );
icl::interval_set< int >() &= 0; icl::interval_set< int >() &= icl::interval< int >::type( 0, 1 );
icl::interval_set< int >() ^= ( icl::interval< int >::type( 0, 1 ) );
They all seem reasonable operations to me. In particular, for a discrete domain, operations like icl::interval_set< int >() += 0 make sense to me. That is the following are equivalent: icl::interval_set< int >() += 0 icl::interval_set< int >() += icl::interval< int >::type( 0, 1 );
Yes, you are right! The code you are giving should compile and it actually compiles on my machine with different msvc compilers. I guess it also compiles for gcc. If the problem persists try to generate a minimal code example so I can look again. Best regards, Joachim -- Interval Container Library [Boost.Icl] http://www.joachim-faulhaber.de
On 24/02/11 11:51, Joachim Faulhaber wrote:
(3) More compilability issues
2011/2/23 John Reid
: I'm interested to hear reasons why the following don't compile when using static bounds:
icl::add( icl::interval_set< int>(), 0 ); icl::add( icl::interval_set< int>(), icl::interval< int>::type( 0, 1 ) ); icl::interval_set< int>() += 0; icl::interval_set< int>() += icl::interval< int>::type( 0, 1 );
icl::subtract( icl::interval_set< int>(), 0 ); icl::subtract( icl::interval_set< int>(), icl::interval< int>::type( 0, 1 ) ); icl::interval_set< int>() -= 0; icl::interval_set< int>() -= icl::interval< int>::type( 0, 1 );
icl::interval_set< int>()&= 0; icl::interval_set< int>()&= icl::interval< int>::type( 0, 1 );
icl::interval_set< int>() ^= ( icl::interval< int>::type( 0, 1 ) );
They all seem reasonable operations to me. In particular, for a discrete domain, operations like icl::interval_set< int>() += 0 make sense to me. That is the following are equivalent: icl::interval_set< int>() += 0 icl::interval_set< int>() += icl::interval< int>::type( 0, 1 );
Yes, you are right! The code you are giving should compile and it actually compiles on my machine with different msvc compilers. I guess it also compiles for gcc. If the problem persists try to generate a minimal code example so I can look again.
We are still talking about static intervals. You did try setting the
#define for static intervals? If you did, then my minimal example
consists of putting the code above in the function f() below:
#define BOOST_ICL_USE_STATIC_BOUNDED_INTERVALS
#include
2011/2/24 John Reid
On 24/02/11 11:51, Joachim Faulhaber wrote:
(3) More compilability issues
2011/2/23 John Reid
: I'm interested to hear reasons why the following don't compile when using static bounds:
icl::add( icl::interval_set< int>(), 0 ); icl::add( icl::interval_set< int>(), icl::interval< int>::type( 0, 1 ) ); icl::interval_set< int>() += 0; icl::interval_set< int>() += icl::interval< int>::type( 0, 1 );
icl::subtract( icl::interval_set< int>(), 0 ); icl::subtract( icl::interval_set< int>(), icl::interval< int>::type( 0, 1 ) ); icl::interval_set< int>() -= 0; icl::interval_set< int>() -= icl::interval< int>::type( 0, 1 );
icl::interval_set< int>()&= 0; icl::interval_set< int>()&= icl::interval< int>::type( 0, 1 );
icl::interval_set< int>() ^= ( icl::interval< int>::type( 0, 1 ) );
They all seem reasonable operations to me. In particular, for a discrete domain, operations like icl::interval_set< int>() += 0 make sense to me. That is the following are equivalent: icl::interval_set< int>() += 0 icl::interval_set< int>() += icl::interval< int>::type( 0, 1 );
Yes, you are right! The code you are giving should compile and it actually compiles on my machine with different msvc compilers. I guess it also compiles for gcc. If the problem persists try to generate a minimal code example so I can look again.
We are still talking about static intervals. You did try setting the #define for static intervals?
Yes.
If you did, then my minimal example consists of putting the code above in the function f() below:
#define BOOST_ICL_USE_STATIC_BOUNDED_INTERVALS #include
#include void f() { namespace icl = ::boost::icl; }
The reason that your code does not compile with gcc but compiles with
msvc is, that gcc is pickier when you try to pass a temporary object
to a reference parameter. When I pass the non-temporary object
'int_set' to the function calls, the code compiles.
#define BOOST_ICL_USE_STATIC_BOUNDED_INTERVALS
#include
On 24/02/11 13:42, Joachim Faulhaber wrote:
The reason that your code does not compile with gcc but compiles with msvc is, that gcc is pickier when you try to pass a temporary object to a reference parameter. When I pass the non-temporary object 'int_set' to the function calls, the code compiles.
Great! Thanks for the help and sorry for the noise, I've seen too many compilation errors recently, I should have caught that one though. Thanks, John.
(4) Using statically and dynamically bounded intervals in the same
compilation unit.
2011/2/23 John Reid
On a side note, I don't understand the rationale for having static bounds configured by #define whilst other aspects of intervals are parameterised using templates.
You can always instantiate ICL interval container templates with the interval type of your choice via the template parameter IntervalT. See e.g. http://www.boost.org/doc/libs/1_46_0/libs/icl/doc/html/boost_icl/interface.h... #define BOOST_ICL_USE_STATIC_BOUNDED_INTERVALS switches the default value for this template-parameter from dynamically bounded to statically bounded intervals. Like any other default of a template parameter you can change it via instantiation. The rational behind this is (1) the intention, to minimize the effort for users, that have applications of ITL containers and want to change their code using statically bounded intervals now. In the ITL every interval was dynamically bounded. (2) for applications that only use one kind of intervals, e.g. statically bounded ones, #define BOOST_ICL_USE_STATIC_BOUNDED_INTERVALS can be convenient, because you need only to specify the first one or two template parameter for interval containers most of the time.
I would have liked to have both types of interval in the same compilation unit. NP
However I guess it must be too late to change this fundamental design choice.
Fortunately it's not too late ;-)
This code shows how to use icl sets with variations of interval types.
BOOST_AUTO_TEST_CASE(using_vaious_interval_types)
{
interval_set
dyn_float_set;
dyn_int_set += discrete_interval<int>(1); BOOST_CHECK(( contains(dyn_int_set,1) )); stat_int_set += right_open_interval<int>(1); BOOST_CHECK(( contains(stat_int_set,1) )); dyn_float_set += continuous_interval<float>(1.0); BOOST_CHECK(( contains(dyn_float_set, 1.0) )); } For interval_map this can get a little verbose, because of the greater number of template parameters. Thank you for your questions. They help to clarify a lot of issues around the library (even for the author:) Joachim -- Interval Container Library [Boost.Icl] http://www.joachim-faulhaber.de
participants (2)
-
Joachim Faulhaber
-
John Reid