$include_dir="/home/hyper-archives/boost-users/include"; include("$include_dir/msg-header.inc") ?>
Subject: [Boost-users] A forward iterator need not be default-constructible
From: Krzysztof Żelechowski (giecrilj_at_[hidden])
Date: 2011-09-26 13:48:26
== Problem ==
The following code fails to compile:
  #include <vector>
  #include <boost/iterator/transform_iterator.hpp>
  #include <boost/range/algorithm.hpp>
  #include <boost/range/adaptor/transformed.hpp>
  static inline void trigger (::std:: vector < int > const &p_v) 
  { 
  /* i: p_v [i] + 0 >= 0 */
  ::boost:: lower_bound 
  (p_v | 
  ::boost:: adaptors:: transformed 
  (::std:: bind1st (::std:: plus < int > (), 0)), 0); }
Details: See [[#Evidence]].
== Workaround ==
The following definition causes the code to compile successfully, as of GNU 
C++ 4.6:
  #define BOOST_RANGE_ENABLE_CONCEPT_ASSERT 0
Disadvantages and risks:
  * The macro BOOST_RANGE_ENABLE_CONCEPT_ASSERT is undocumented.
  * It disables concept checking altogether, which may be a good thing or a 
bad thing, depending on your needs.  The official motivation for concept 
checking is that it makes error messages more readable; in this particular 
case, I am not convinced.
== Background ==
TL;DR: If all you can say is that such an iterator does not meet the 
requirements imposed by the standard, I am not interested.  If you are 
willing not to treat the standard as the ultimate and unquestionable oracle, 
you may read on :-)
The standard C++ library defined iterators to serve and additional task to 
serve as abstract pointers that may be singular, i.e. not corresponding to 
any object and distinct from any other iterator.  To this end, the standard 
requires that interators may be constructed out of thin air, and that such 
an iterator is singular.  This requirement is only useful iterators that do 
not correspond to containers like the standard input stream iterator which 
you can use to find something in it, and even then the end iterator, which 
is singular, is created explicitly by the calling code and not by library 
code.  
Requiring conformance to this particular requirement in Boost is 
counterproductive, as it causes perfectly valid and obvious code to fail to 
compile for no reason at all except for respecting the letter of the 
standard.
== Conclusions ==
  1. The macro BOOST_RANGE_ENABLE_CONCEPT_ASSERT should be documented, as it 
is necessary to keep the concepts BS at bay.
  2. The concept mechanism used by Boost should not require singular 
iterators to exist; the standard is obnoxious and misguided here and 
promotes sloppy coding.
== Note ==
I believe that it is possible to design algorithms so that they do not 
construct singular iterators anywhere; moreover, I believe that doing so 
would be beneficial to the library implementation, as evidenced in GNU 
libstdc++ Bug #45488.  (My similar report against Plaugerâs library was 
declined by Microsoft, which means I have to use a replacement algorithm 
fixed by myself.)
== Evidence ==
g++ -g    doit.cpp   -o doit
In file included from doit.cpp:4:0:
/usr/include/boost/iterator/transform_iterator.hpp: In constructor 
âboost::transform_iterator<UnaryFunction, Iterator, Reference, 
Value>::transform_iterator() [with UnaryFunc = std::binder1st<std::plus<int> 
>, Iterator = __gnu_cxx::__normal_iterator<const int*, std::vector<int> >, 
Reference = boost::use_default, Value = boost::use_default]â:
/usr/include/boost/concept_check.hpp:130:10:   instantiated from 
âboost::DefaultConstructible<TT>::~DefaultConstructible() [with TT = 
boost::transform_iterator<std::binder1st<std::plus<int> >, 
__gnu_cxx::__normal_iterator<const int*, std::vector<int> >, 
boost::use_default, boost::use_default>]â
/usr/include/boost/range/concepts.hpp:148:16:   instantiated from âstatic 
void boost::concepts::requirement<boost::concepts::failed************ 
Model::************>::failed() [with Model = 
boost::range_detail::ForwardIteratorConcept<
boost::transform_iterator<std::binder1st<std::plus<int> >, 
__gnu_cxx::__normal_iterator<const int*, std::vector<int> >, 
boost::use_default, boost::use_default> >]â
/usr/include/boost/range/concepts.hpp:264:1:   instantiated from 
âboost::ForwardRangeConcept<const 
boost::range_detail::transform_range<std::binder1st<std::plus<int> >, const 
std::vector<int> > >â
/usr/include/boost/concept/detail/has_constraints.hpp:42:5:   instantiated 
from âconst bool 
boost::concepts::not_satisfied<boost::ForwardRangeConcept<const 
boost::range_detail::transform_range<std::binder1st<std::plus<int> >, const 
std::vector<int> > > >::valueâ
/usr/include/boost/concept/detail/has_constraints.hpp:45:31:   instantiated 
from âboost::concepts::not_satisfied<boost::ForwardRangeConcept<const 
boost::range_detail::transform_range<std::binder1st<std::plus<int> >, const 
std::vector<int> > > >â
/usr/include/boost/mpl/if.hpp:67:11:   instantiated from âboost::mpl::if_
<boost::concepts::not_satisfied<boost::ForwardRangeConcept<const 
boost::range_detail::transform_range<std::binder1st<std::plus<int> >, const 
std::vector<int> > > >, 
boost::concepts::constraint<boost::ForwardRangeConcept<const 
boost::range_detail::transform_range<std::binder1st<std::plus<int> >, const 
std::vector<int> > > >, 
boost::concepts::requirement<boost::concepts::failed************ 
boost::ForwardRangeConcept<const 
boost::range_detail::transform_range<std::binder1st<std::plus<int> >, const 
std::vector<int> > >::************> >â
/usr/include/boost/concept/detail/general.hpp:50:8:   instantiated from 
âboost::concepts::requirement_<void (*)(boost::ForwardRangeConcept<const 
boost::range_detail::transform_range<std::binder1st<std::plus<int> >, const 
std::vector<int> > >)>â
/usr/include/boost/range/algorithm/lower_bound.hpp:45:1:   instantiated from 
âtypename boost::range_iterator<const ForwardRange>::type 
boost::range::lower_bound(const ForwardRange&, Value) [with ForwardRange = 
boost::range_detail::transform_range<std::binder1st<std::plus<int> >, const 
std::vector<int> >, Value = int, typename boost::range_iterator<const 
ForwardRange>::type = 
boost::transform_iterator<std::binder1st<std::plus<int> >, 
__gnu_cxx::__normal_iterator<const int*, std::vector<int> >, 
boost::use_default, boost::use_default>]â
doit.cpp:8:114:   instantiated from here
/usr/include/boost/iterator/transform_iterator.hpp:99:26: error: no matching 
function for call to âstd::binder1st<std::plus<int> >::binder1st()â
/usr/include/boost/iterator/transform_iterator.hpp:99:26: note: candidates 
are:
/usr/include/c++/4.6/backward/binders.h:109:7: note: 
std::binder1st<_Operation>::binder1st(const _Operation&, const typename 
_Operation::first_argument_type&) [with _Operation = std::plus<int>, 
typename _Operation::first_argument_type = int]
/usr/include/c++/4.6/backward/binders.h:109:7: note:   candidate expects 2 
arguments, 0 provided
/usr/include/c++/4.6/backward/binders.h:100:11: note: 
std::binder1st<std::plus<int> >::binder1st(const 
std::binder1st<std::plus<int> >&)
/usr/include/c++/4.6/backward/binders.h:100:11: note:   candidate expects 1 
argument, 0 provided
Kompilacja nie powiodÅa siÄ
make: *** [doit] BÅÄ
d 1