[Range] make range_const/mutable_iterator<C>::type non-existent if C is non-range

Hello, the attached patch makes boost::range_const/mutable_iterator<C>::type non-existent if C does not have the right typedef C::(const_)iterator. For me, this fixed a compilation error in the following situation: template<class Rng, class Val, class BinPred> typename boost::range_const_iterator<Rng>::type lower_bound(Rng const& rng,Val const& x,BinPred pred); // not taken template<class It, class Val, class BinPred> It lower_bound(It itBegin,It itEnd,Val const& x) { // taken return itBegin; // dummy } main() { std::vector<int> vecn; int n=6; lower_bound( vecn.begin(), vecn.end(), n ); } The return type of the overload that is not taken is range_const_iterator< std::vector<int>::iterator >::type. With the old range_const_iterator, this typedef exists, which makes the overload compile, but evaluates to std::vector<int>::iterator::const_iterator, which does not exist and causes a compiler error. With the patch, range_const_iterator< std::vector<int>::iterator >::type already does not exist, and the compiler aborts checking this overload. I don't see a way to fix this without changing or largely reimplementing range_const_iterator, because the mere presence of the "type" typedef in the default case of range_const_iterator causes the problem. Any chance to get this adopted? Arno -- Dr. Arno Schoedl · aschoedl@think-cell.com Technical Director think-cell Software GmbH · Invalidenstr. 34 · 10115 Berlin, Germany http://www.think-cell.com · phone +49-30-666473-10 · toll-free (US) +1-800-891-8091 Directors: Dr. Markus Hannebauer, Dr. Arno Schoedl · Amtsgericht Charlottenburg, HRB 85229

On Tue, Dec 30, 2008 at 6:09 PM, Arno Schödl <aschoedl@think-cell.com>wrote:
Hello,
the attached patch makes boost::range_const/mutable_iterator<C>::type non-existent if C does not have the right typedef C::(const_)iterator. For me, this fixed a compilation error in the following situation:
template<class Rng, class Val, class BinPred> typename boost::range_const_iterator<Rng>::type lower_bound(Rng const& rng,Val const& x,BinPred pred); // not taken
template<class It, class Val, class BinPred> It lower_bound(It itBegin,It itEnd,Val const& x) { // taken return itBegin; // dummy }
main() { std::vector<int> vecn; int n=6; lower_bound( vecn.begin(), vecn.end(), n ); }
The return type of the overload that is not taken is range_const_iterator< std::vector<int>::iterator >::type. With the old range_const_iterator, this typedef exists, which makes the overload compile, but evaluates to std::vector<int>::iterator::const_iterator, which does not exist and causes a compiler error. With the patch, range_const_iterator< std::vector<int>::iterator >::type already does not exist, and the compiler aborts checking this overload. I don't see a way to fix this without changing or largely reimplementing range_const_iterator, because the mere presence of the "type" typedef in the default case of range_const_iterator causes the problem.
Any chance to get this adopted?
I have taken some time to evaluate alternative solutions, but I think the proposed patch is the best solution available. I am, with your permission, going to put this into the RangeEx code in the vault. This will, if all goes to plan, subsequently be an update of Boost.Range. It seems that this type of solution would be applicable to the mutable and reverse variants. Do you agree?
Arno
-- Dr. Arno Schoedl · aschoedl@think-cell.com Technical Director
think-cell Software GmbH · Invalidenstr. 34 · 10115 Berlin, Germany http://www.think-cell.com · phone +49-30-666473-10 · toll-free (US) +1-800-891-8091 Directors: Dr. Markus Hannebauer, Dr. Arno Schoedl · Amtsgericht Charlottenburg, HRB 85229
Thank you for the patch. Neil Groves

I have taken some time to evaluate alternative solutions, but I think the proposed patch is the best solution available. I am, with your permission, going to put this into the RangeEx code in the vault. This will, if all goes to plan, subsequently be an update of Boost.Range. It seems that this type of solution would be applicable to the mutable and reverse variants. Do you agree?
Feel free to put it in. The same principle applies to all templates exposing typedefs in their default implementation. I think this is a frequent pattern in Boost.Iterator, Boost.Range and Boost.MPL: template< class T > struct wrapper { typedef typename T::some_typedef type; }; You can always make it break like this: template< class T > typename wrapper<T>::type Func( T t ) {}; template< class T > void Func( T t ) {}; main () { struct {} empty_struct; func( empty_struct ); } and then fix it like this: BOOST_EXTRACT_OPTIONAL_TYPE( some_typedef ); template< class T > struct wrapper : extract_some_typedef<T> {}; I already patched boost::range_mutable_iterator because I also use it as return type (see patch posted earlier). I am not sure how far we should drive this. We may not know all side effects yet, and whether my fix is really the best one. Maybe we should do it where immediately needed and otherwise wait for more evidence. Arno -- Dr. Arno Schoedl · aschoedl@think-cell.com Technical Director think-cell Software GmbH · Invalidenstr. 34 · 10115 Berlin, Germany http://www.think-cell.com · phone +49-30-666473-10 · toll-free (US) +1-800-891-8091 Directors: Dr. Markus Hannebauer, Dr. Arno Schoedl · Amtsgericht Charlottenburg, HRB 85229

Arno Schödl skrev:
Hello,
the attached patch makes boost::range_const/mutable_iterator<C>::type non-existent if C does not have the right typedef C::(const_)iterator. For me, this fixed a compilation error in the following situation:
template<class Rng, class Val, class BinPred> typename boost::range_const_iterator<Rng>::type lower_bound(Rng const& rng,Val const& x,BinPred pred); // not taken
template<class It, class Val, class BinPred> It lower_bound(It itBegin,It itEnd,Val const& x) { // taken return itBegin; // dummy }
main() { std::vector<int> vecn; int n=6; lower_bound( vecn.begin(), vecn.end(), n ); }
The return type of the overload that is not taken is range_const_iterator< std::vector<int>::iterator >::type. With the old range_const_iterator, this typedef exists, which makes the overload compile, but evaluates to std::vector<int>::iterator::const_iterator, which does not exist and causes a compiler error. With the patch, range_const_iterator< std::vector<int>::iterator >::type already does not exist, and the compiler aborts checking this overload. I don't see a way to fix this without changing or largely reimplementing range_const_iterator, because the mere presence of the "type" typedef in the default case of range_const_iterator causes the problem.
Any chance to get this adopted?
It seems like a reasonable problem to solve. Neil, what other solutions did you think about? Another question: is your fix widely portable? -Thorsten

It seems like a reasonable problem to solve. Neil, what other solutions did you think about?
Another question: is your fix widely portable?
I have no idea. Our partition_point unit tests will check that. I just checked in a fall-back for BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION (and renamed it to lazy_typedef, similar to lazy_enable_if): http://svn.boost.org/svn/boost/sandbox/partition_point/boost/partition_point... Arno -- Dr. Arno Schoedl · aschoedl@think-cell.com Technical Director think-cell Software GmbH · Invalidenstr. 34 · 10115 Berlin, Germany http://www.think-cell.com · phone +49-30-666473-10 · toll-free (US) +1-800-891-8091 Directors: Dr. Markus Hannebauer, Dr. Arno Schoedl · Amtsgericht Charlottenburg, HRB 85229

Any chance to get this adopted?
It seems like a reasonable problem to solve. Neil, what other solutions did you think about?
Another question: is your fix widely portable?
Thorsten, is it o.k. if I add these Boost.Range changes to my "partition_point" library, so it will be reviewed and adopted as a package? I'd put lazy_typedef into boost::detail::range. Arno -- Dr. Arno Schoedl · aschoedl@think-cell.com Technical Director think-cell Software GmbH · Invalidenstr. 34 · 10115 Berlin, Germany http://www.think-cell.com · phone +49-30-666473-10 · toll-free (US) +1-800-891-8091 Directors: Dr. Markus Hannebauer, Dr. Arno Schoedl · Amtsgericht Charlottenburg, HRB 85229

Arno Schödl skrev:
Any chance to get this adopted? It seems like a reasonable problem to solve. Neil, what other solutions did you think about?
Another question: is your fix widely portable?
Thorsten,
is it o.k. if I add these Boost.Range changes to my "partition_point" library, so it will be reviewed and adopted as a package? I'd put lazy_typedef into boost::detail::range.
I don't see why not. As for the portability, I guess we can test that on trunk. I'll see if I can get some time to do this... -Thorsten

Thorsten,
is it o.k. if I add these Boost.Range changes to my "partition_point" library, so it will be reviewed and adopted as a package? I'd put lazy_typedef into boost::detail::range.
I don't see why not. As for the portability, I guess we can test that on trunk. I'll see if I can get some time to do this...
partition_point library will test this for its use cases, which covers the relevant ones: - use as return value, - use as parameter, - overload disambiguation on it. Arno -- Dr. Arno Schoedl · aschoedl@think-cell.com Technical Director think-cell Software GmbH · Invalidenstr. 34 · 10115 Berlin, Germany http://www.think-cell.com · phone +49-30-666473-10 · toll-free (US) +1-800-891-8091 Directors: Dr. Markus Hannebauer, Dr. Arno Schoedl · Amtsgericht Charlottenburg, HRB 85229

Arno Schödl skrev:
Thorsten,
is it o.k. if I add these Boost.Range changes to my "partition_point" library, so it will be reviewed and adopted as a package? I'd put lazy_typedef into boost::detail::range.
I don't see why not. As for the portability, I guess we can test that on trunk. I'll see if I can get some time to do this...
partition_point library will test this for its use cases, which covers the relevant ones:
- use as return value, - use as parameter, - overload disambiguation on it.
Ok, so if it works as portable as Boost.Range, then we can add it to trunk and then it will be part of 1.39. -Thorsten
participants (3)
-
Arno Schödl
-
Neil Groves
-
Thorsten Ottosen