ericniebler / range-v3

Range library for C++14/17/20, basis for C++20's std::ranges
Other
4.11k stars 442 forks source link

Compilation failure connected to Boost, possibly due to #486 #497

Closed tonyelewis closed 7 years ago

tonyelewis commented 7 years ago

The following fails to compile under both GCC and Clang (errors attached):

#include <boost/optional.hpp>
#include <boost/range.hpp>

#define RANGES_NO_STD_FORWARD_DECLARATIONS
#include <range/v3/all.hpp>

#include <vector>

int main() {
    const std::vector< boost::optional< int > > &a = { 1, 2, 3, 4, 5 };
    const std::vector<int> b = a
        | ranges::view::remove_if( [] (const boost::optional<int> &x) { return ! x;     } )
        | ranges::view::transform( [] (const boost::optional<int> &x) { return x.get(); } );
}

Interestingly the problem disappears if I simplify to int rather than optional<int>:

const std::vector< int > a = { 1, 2, 3, 4, 5 };
const std::vector< int > b = a
    | ranges::view::remove_if( [] (const int &x) { return ( x % 2 == 0 ); } )
    | ranges::view::transform( [] (const int &x) { return x + 1; } );

I think this relates to the changes I proposed and added in #486. My apologies if it caused by them.

As you can see below, at size.hpp:41, the error stack moves into Boost, which is due to a call size(rng);.

Later it fails on a decltype call to a non-member begin of the const remove_if_view<...> &. Although there may be some issues with the const, I don't think that's the whole issue because the same sort of problem remains if I tweak RANGES_SATISFY_BOOST_RANGE() to drop the const.

Start of GCC errors:

In file included from range_v3_include/range/v3/range_traits.hpp:24:0,
                 from range_v3_include/range/v3/distance.hpp:22,
                 from range_v3_include/range/v3/core.hpp:18,
                 from range_v3_include/range/v3/all.hpp:17,
                 from range_v3_prob.cpp:5:
range_v3_include/range/v3/range_concepts.hpp: In substitution of ‘template<class T> using iterator_t = decltype (ranges::v3::{anonymous}::begin(declval<T&>())) [with T = const ranges::v3::remove_if_view<ranges::v3::iterator_range<__gnu_cxx::__normal_iterator<const boost::optional<int>*, std::vector<boost::optional<int> > >, __gnu_cxx::__normal_iterator<const boost::optional<int>*, std::vector<boost::optional<int> > > >, main()::<lambda(const boost::optional<int>&)> >]’:
range_v3_include/range/v3/range_traits.hpp:35:66:   required by substitution of ‘template<class Rng> using range_iterator_t = ranges::v3::concepts::Range::iterator_t<T> [with Rng = const ranges::v3::remove_if_view<ranges::v3::iterator_range<__gnu_cxx::__normal_iterator<const boost::optional<int>*, std::vector<boost::optional<int> > >, __gnu_cxx::__normal_iterator<const boost::optional<int>*, std::vector<boost::optional<int> > > >, main()::<lambda(const boost::optional<int>&)> >]’
range_v3_include/range/v3/view/remove_if.hpp:185:1:   required from ‘struct boost::range_const_iterator<ranges::v3::remove_if_view<ranges::v3::iterator_range<__gnu_cxx::__normal_iterator<const boost::optional<int>*, std::vector<boost::optional<int> > >, __gnu_cxx::__normal_iterator<const boost::optional<int>*, std::vector<boost::optional<int> > > >, main()::<lambda(const boost::optional<int>&)> >, void>’
boost_include/boost/range/iterator.hpp:61:12:   required from ‘struct boost::range_iterator<const ranges::v3::remove_if_view<ranges::v3::iterator_range<__gnu_cxx::__normal_iterator<const boost::optional<int>*, std::vector<boost::optional<int> > >, __gnu_cxx::__normal_iterator<const boost::optional<int>*, std::vector<boost::optional<int> > > >, main()::<lambda(const boost::optional<int>&)> >, void>’
boost_include/boost/range/concepts.hpp:272:17:   required from ‘struct boost::SinglePassRangeConcept<ranges::v3::remove_if_view<ranges::v3::iterator_range<__gnu_cxx::__normal_iterator<const boost::optional<int>*, std::vector<boost::optional<int> > >, __gnu_cxx::__normal_iterator<const boost::optional<int>*, std::vector<boost::optional<int> > > >, main()::<lambda(const boost::optional<int>&)> > >’
boost_include/boost/concept/detail/has_constraints.hpp:32:62:   required by substitution of ‘template<class Model> boost::concepts::detail::yes boost::concepts::detail::has_constraints_(Model*, boost::concepts::detail::wrap_constraints<Model, (& Model:: constraints)>*) [with Model = boost::SinglePassRangeConcept<ranges::v3::remove_if_view<ranges::v3::iterator_range<__gnu_cxx::__normal_iterator<const boost::optional<int>*, std::vector<boost::optional<int> > >, __gnu_cxx::__normal_iterator<const boost::optional<int>*, std::vector<boost::optional<int> > > >, main()::<lambda(const boost::optional<int>&)> > >]’
boost_include/boost/concept/detail/has_constraints.hpp:42:5:   required from ‘const bool boost::concepts::not_satisfied<boost::SinglePassRangeConcept<ranges::v3::remove_if_view<ranges::v3::iterator_range<__gnu_cxx::__normal_iterator<const boost::optional<int>*, std::vector<boost::optional<int> > >, __gnu_cxx::__normal_iterator<const boost::optional<int>*, std::vector<boost::optional<int> > > >, main()::<lambda(const boost::optional<int>&)> > > >::value’
boost_include/boost/concept/detail/has_constraints.hpp:45:31:   required from ‘struct boost::concepts::not_satisfied<boost::SinglePassRangeConcept<ranges::v3::remove_if_view<ranges::v3::iterator_range<__gnu_cxx::__normal_iterator<const boost::optional<int>*, std::vector<boost::optional<int> > >, __gnu_cxx::__normal_iterator<const boost::optional<int>*, std::vector<boost::optional<int> > > >, main()::<lambda(const boost::optional<int>&)> > > >’
boost_include/boost/mpl/if.hpp:63:11:   required from ‘struct boost::mpl::if_<boost::concepts::not_satisfied<boost::SinglePassRangeConcept<ranges::v3::remove_if_view<ranges::v3::iterator_range<__gnu_cxx::__normal_iterator<const boost::optional<int>*, std::vector<boost::optional<int> > >, __gnu_cxx::__normal_iterator<const boost::optional<int>*, std::vector<boost::optional<int> > > >, main()::<lambda(const boost::optional<int>&)> > > >, boost::concepts::constraint<boost::SinglePassRangeConcept<ranges::v3::remove_if_view<ranges::v3::iterator_range<__gnu_cxx::__normal_iterator<const boost::optional<int>*, std::vector<boost::optional<int> > >, __gnu_cxx::__normal_iterator<const boost::optional<int>*, std::vector<boost::optional<int> > > >, main()::<lambda(const boost::optional<int>&)> > > >, boost::concepts::requirement<boost::concepts::failed************ boost::SinglePassRangeConcept<ranges::v3::remove_if_view<ranges::v3::iterator_range<__gnu_cxx::__normal_iterator<const boost::optional<int>*, std::vector<boost::optional<int> > >, __gnu_cxx::__normal_iterator<const boost::optional<int>*, std::vector<boost::optional<int> > > >, main()::<lambda(const boost::optional<int>&)> > >::************> >’
boost_include/boost/concept/detail/general.hpp:51:8:   required from ‘struct boost::concepts::requirement_<void (*)(boost::SinglePassRangeConcept<ranges::v3::remove_if_view<ranges::v3::iterator_range<__gnu_cxx::__normal_iterator<const boost::optional<int>*, std::vector<boost::optional<int> > >, __gnu_cxx::__normal_iterator<const boost::optional<int>*, std::vector<boost::optional<int> > > >, main()::<lambda(const boost::optional<int>&)> > >)>’
boost_include/boost/range/size.hpp:62:9:   required from ‘typename boost::range_size<const T>::type boost::size(const SinglePassRange&) [with SinglePassRange = ranges::v3::remove_if_view<ranges::v3::iterator_range<__gnu_cxx::__normal_iterator<const boost::optional<int>*, std::vector<boost::optional<int> > >, __gnu_cxx::__normal_iterator<const boost::optional<int>*, std::vector<boost::optional<int> > > >, main()::<lambda(const boost::optional<int>&)> >; typename boost::range_size<const T>::type = long unsigned int]’
range_v3_include/range/v3/size.hpp:41:28:   required from ‘constexpr Result ranges::v3::adl_size_detail::impl(Rng&&, long int) [with Rng = const ranges::v3::remove_if_view<ranges::v3::iterator_range<__gnu_cxx::__normal_iterator<const boost::optional<int>*, std::vector<boost::optional<int> > >, __gnu_cxx::__normal_iterator<const boost::optional<int>*, std::vector<boost::optional<int> > > >, main()::<lambda(const boost::optional<int>&)> >&; Result = long unsigned int; int _concept_requires_37 = 42; typename std::enable_if<((_concept_requires_37 == 43) || ranges::v3::concepts::models<ranges::v3::concepts::Integral, Result>()), int>::type <anonymous> = 0]’
range_v3_include/range/v3/size.hpp:91:32:   required from ‘constexpr decltype (ranges::v3::adl_size_detail::impl(forward<Rng>(rng), 42)) ranges::v3::adl_size_detail::size_fn::operator()(Rng&&) const [with Rng = const ranges::v3::remove_if_view<ranges::v3::iterator_range<__gnu_cxx::__normal_iterator<const boost::optional<int>*, std::vector<boost::optional<int> > >, __gnu_cxx::__normal_iterator<const boost::optional<int>*, std::vector<boost::optional<int> > > >, main()::<lambda(const boost::optional<int>&)> >&; decltype (ranges::v3::adl_size_detail::impl(forward<Rng>(rng), 42)) = long unsigned int]’
range_v3_include/range/v3/range_concepts.hpp:164:29:   required by substitution of ‘template<class T> decltype (ranges::v3::detail::valid_expr(ranges::v3::detail::is_false(ranges::v3::disable_sized_range<typename std::remove_cv<typename std::remove_reference<_From>::type>::type>()), ranges::v3::{anonymous}::size(t))) ranges::v3::concepts::SizedRange::requires_(T&&) [with T = const ranges::v3::remove_if_view<ranges::v3::iterator_range<__gnu_cxx::__normal_iterator<const boost::optional<int>*, std::vector<boost::optional<int> > >, __gnu_cxx::__normal_iterator<const boost::optional<int>*, std::vector<boost::optional<int> > > >, main()::<lambda(const boost::optional<int>&)> >]’
range_v3_include/range/v3/utility/concepts.hpp:113:17:   required by substitution of ‘template<class ... Ts, class Concept, class> meta::v1::apply<meta::v1::quote<meta::v1::lazy::strict_and>, typename meta::v1::detail::transform_<meta::v1::list<typename ranges::v3::detail::base_concepts_of<Concept, void>::type, meta::v1::bind_back<meta::v1::quote<ranges::v3::concepts::models>, Ts ...> >, void>::type> ranges::v3::detail::models_(Concept*) [with Ts = {const ranges::v3::remove_if_view<ranges::v3::iterator_range<__gnu_cxx::__normal_iterator<const boost::optional<int>*, std::vector<boost::optional<int>, std::allocator<boost::optional<int> > > >, __gnu_cxx::__normal_iterator<const boost::optional<int>*, std::vector<boost::optional<int>, std::allocator<boost::optional<int> > > > >, main()::<lambda(const boost::optional<int>&)> >}; Concept = ranges::v3::concepts::SizedRange; <template-parameter-1-3> = void]’
range_v3_include/range/v3/utility/concepts.hpp:212:69:   required from ‘struct ranges::v3::concepts::models<ranges::v3::concepts::SizedRange, const ranges::v3::remove_if_view<ranges::v3::iterator_range<__gnu_cxx::__normal_iterator<const boost::optional<int>*, std::vector<boost::optional<int>, std::allocator<boost::optional<int> > > >, __gnu_cxx::__normal_iterator<const boost::optional<int>*, std::vector<boost::optional<int>, std::allocator<boost::optional<int> > > > >, main()::<lambda(const boost::optional<int>&)> > >’
range_v3_include/range/v3/view/transform.hpp:117:13:   required from ‘struct ranges::v3::iter_transform_view<ranges::v3::remove_if_view<ranges::v3::iterator_range<__gnu_cxx::__normal_iterator<const boost::optional<int>*, std::vector<boost::optional<int> > >, __gnu_cxx::__normal_iterator<const boost::optional<int>*, std::vector<boost::optional<int> > > >, main()::<lambda(const boost::optional<int>&)> >, ranges::v3::indirected<main()::<lambda(const boost::optional<int>&)> > >’
range_v3_include/range/v3/view/transform.hpp:130:16:   required from ‘struct ranges::v3::transform_view<ranges::v3::remove_if_view<ranges::v3::iterator_range<__gnu_cxx::__normal_iterator<const boost::optional<int>*, std::vector<boost::optional<int> > >, __gnu_cxx::__normal_iterator<const boost::optional<int>*, std::vector<boost::optional<int> > > >, main()::<lambda(const boost::optional<int>&)> >, main()::<lambda(const boost::optional<int>&)> >’
range_v3_include/range/v3/utility/concepts.hpp:708:42:   required by substitution of ‘template<class Fun, class ... Args> decltype (ranges::v3::detail::valid_expr(model_of<ranges::v3::concepts::CopyConstructible, ranges::v3::uncvref_t<T> >(), ((void)(val<Fun>()((val<Args>)()...)), 42))) ranges::v3::concepts::Function::requires_(Fun&&, Args&& ...) [with Fun = ranges::v3::detail::pipeable_binder<std::_Bind<ranges::v3::view::transform_fn(std::_Placeholder<1>, main()::<lambda(const boost::optional<int>&)>)> >; Args = {ranges::v3::remove_if_view<ranges::v3::iterator_range<__gnu_cxx::__normal_iterator<const boost::optional<int>*, std::vector<boost::optional<int>, std::allocator<boost::optional<int> > > >, __gnu_cxx::__normal_iterator<const boost::optional<int>*, std::vector<boost::optional<int>, std::allocator<boost::optional<int> > > > >, main()::<lambda(const boost::optional<int>&)> >}]’
range_v3_include/range/v3/utility/concepts.hpp:113:17:   required by substitution of ‘template<class ... Ts, class Concept, class> meta::v1::apply<meta::v1::quote<meta::v1::lazy::strict_and>, typename meta::v1::detail::transform_<meta::v1::list<typename ranges::v3::detail::base_concepts_of<Concept, void>::type, meta::v1::bind_back<meta::v1::quote<ranges::v3::concepts::models>, Ts ...> >, void>::type> ranges::v3::detail::models_(Concept*) [with Ts = {ranges::v3::detail::pipeable_binder<std::_Bind<ranges::v3::view::transform_fn(std::_Placeholder<1>, main()::<lambda(const boost::optional<int>&)>)> >, ranges::v3::remove_if_view<ranges::v3::iterator_range<__gnu_cxx::__normal_iterator<const boost::optional<int>*, std::vector<boost::optional<int>, std::allocator<boost::optional<int> > > >, __gnu_cxx::__normal_iterator<const boost::optional<int>*, std::vector<boost::optional<int>, std::allocator<boost::optional<int> > > > >, main()::<lambda(const boost::optional<int>&)> >}; Concept = ranges::v3::concepts::Function; <template-parameter-1-3> = void]’
range_v3_include/range/v3/utility/concepts.hpp:212:69:   required from ‘struct ranges::v3::concepts::models<ranges::v3::concepts::Function, ranges::v3::detail::pipeable_binder<std::_Bind<ranges::v3::view::transform_fn(std::_Placeholder<1>, main()::<lambda(const boost::optional<int>&)>)> >, ranges::v3::remove_if_view<ranges::v3::iterator_range<__gnu_cxx::__normal_iterator<const boost::optional<int>*, std::vector<boost::optional<int>, std::allocator<boost::optional<int> > > >, __gnu_cxx::__normal_iterator<const boost::optional<int>*, std::vector<boost::optional<int>, std::allocator<boost::optional<int> > > > >, main()::<lambda(const boost::optional<int>&)> > >’
range_v3_include/meta/meta.hpp:1138:24:   required from ‘struct meta::v1::detail::_and_<ranges::v3::concepts::models<ranges::v3::concepts::Function, ranges::v3::detail::pipeable_binder<std::_Bind<ranges::v3::view::transform_fn(std::_Placeholder<1>, main()::<lambda(const boost::optional<int>&)>)> >, ranges::v3::remove_if_view<ranges::v3::iterator_range<__gnu_cxx::__normal_iterator<const boost::optional<int>*, std::vector<boost::optional<int>, std::allocator<boost::optional<int> > > >, __gnu_cxx::__normal_iterator<const boost::optional<int>*, std::vector<boost::optional<int>, std::allocator<boost::optional<int> > > > >, main()::<lambda(const boost::optional<int>&)> > > >’
range_v3_include/meta/meta.hpp:1137:20:   required from ‘struct meta::v1::detail::_and_<std::integral_constant<bool, true>, ranges::v3::concepts::models<ranges::v3::concepts::Function, ranges::v3::detail::pipeable_binder<std::_Bind<ranges::v3::view::transform_fn(std::_Placeholder<1>, main()::<lambda(const boost::optional<int>&)>)> >, ranges::v3::remove_if_view<ranges::v3::iterator_range<__gnu_cxx::__normal_iterator<const boost::optional<int>*, std::vector<boost::optional<int>, std::allocator<boost::optional<int> > > >, __gnu_cxx::__normal_iterator<const boost::optional<int>*, std::vector<boost::optional<int>, std::allocator<boost::optional<int> > > > >, main()::<lambda(const boost::optional<int>&)> > > >’
range_v3_include/range/v3/view/view.hpp:90:21:   required by substitution of ‘template<class Rng, class Vw, int _concept_requires_90, typename std::enable_if<((_concept_requires_90 == 43) || typename meta::v1::detail::_and_<typename meta::v1::detail::_and_<ranges::v3::concepts::models<ranges::v3::concepts::Range, T>, typename meta::v1::detail::_or_<std::is_lvalue_reference<_Tp>, ranges::v3::concepts::models<ranges::v3::concepts::View, T> >::type>::type, ranges::v3::concepts::models<ranges::v3::concepts::Function, ranges::v3::detail::pipeable_binder<std::_Bind<ranges::v3::view::transform_fn(std::_Placeholder<1>, main()::<lambda(const boost::optional<int>&)>)> >, Rng> >::type()), int>::type <anonymous> > static decltype (v.view_(forward<Rng>(rng))) ranges::v3::view::view<View>::pipe(Rng&&, Vw&&) [with Rng = ranges::v3::remove_if_view<ranges::v3::iterator_range<__gnu_cxx::__normal_iterator<const boost::optional<int>*, std::vector<boost::optional<int> > >, __gnu_cxx::__normal_iterator<const boost::optional<int>*, std::vector<boost::optional<int> > > >, main()::<lambda(const boost::optional<int>&)> >; Vw = ranges::v3::view::view<ranges::v3::detail::pipeable_binder<std::_Bind<ranges::v3::view::transform_fn(std::_Placeholder<1>, main()::<lambda(const boost::optional<int>&)>)> > >&; int _concept_requires_90 = 42; typename std::enable_if<((_concept_requires_90 == 43) || typename meta::v1::detail::_and_<typename meta::v1::detail::_and_<ranges::v3::concepts::models<ranges::v3::concepts::Range, T>, typename meta::v1::detail::_or_<std::is_lvalue_reference<_Tp>, ranges::v3::concepts::models<ranges::v3::concepts::View, T> >::type>::type, ranges::v3::concepts::models<ranges::v3::concepts::Function, ranges::v3::detail::pipeable_binder<std::_Bind<ranges::v3::view::transform_fn(std::_Placeholder<1>, main()::<lambda(const boost::optional<int>&)>)> >, Rng> >::type()), int>::type <anonymous> = 0]’
range_v3_include/range/v3/utility/functional.hpp:767:9:   required by substitution of ‘template<class Arg, class Pipe, int _concept_requires_765, typename std::enable_if<((_concept_requires_765 == 43) || ((! ranges::v3::is_pipeable<T>()) && ranges::v3::is_pipeable<Pipe>())), int>::type <anonymous> > decltype (ranges::v3::pipeable_access::impl<Pipe>::pipe(forward<Arg>(arg), pipe)) ranges::v3::operator|(Arg&&, Pipe) [with Arg = ranges::v3::remove_if_view<ranges::v3::iterator_range<__gnu_cxx::__normal_iterator<const boost::optional<int>*, std::vector<boost::optional<int> > >, __gnu_cxx::__normal_iterator<const boost::optional<int>*, std::vector<boost::optional<int> > > >, main()::<lambda(const boost::optional<int>&)> >; Pipe = ranges::v3::view::view<ranges::v3::detail::pipeable_binder<std::_Bind<ranges::v3::view::transform_fn(std::_Placeholder<1>, main()::<lambda(const boost::optional<int>&)>)> > >; int _concept_requires_765 = 42; typename std::enable_if<((_concept_requires_765 == 43) || ((! ranges::v3::is_pipeable<T>()) && ranges::v3::is_pipeable<Pipe>())), int>::type <anonymous> = 0]’
range_v3_prob.cpp:13:85:   required from here
range_v3_include/range/v3/range_concepts.hpp:63:50: error: no match for call to ‘(const ranges::v3::adl_begin_end_detail::begin_fn) (const ranges::v3::remove_if_view<ranges::v3::iterator_range<__gnu_cxx::__normal_iterator<const boost::optional<int>*, std::vector<boost::optional<int> > >, __gnu_cxx::__normal_iterator<const boost::optional<int>*, std::vector<boost::optional<int> > > >, main()::<lambda(const boost::optional<int>&)> >&)’
                 using iterator_t = decltype(begin(std::declval<T&>()));
                                             ~~~~~^~~~~~~~~~~~~~~~~~~~

Can you see what's going on here? Many thanks for your help.

clang_errors.colour.txt clang_errors.txt gcc_errors.txt gcc_errors.colour.txt

ericniebler commented 7 years ago

My guess: using boost::optional makes boost an associated namespace, so calls to begin are finding boost::begin. And boost::begin is statically asserting that it's argument satisfies its notion of SinglePassRange. The range-v3 range concepts do not perfectly overlap with the Boost range concepts. In particular, a range type R might have an end that returns a different type than begin. Also, R may be a range while R const is not.

TL;DR we need to constrain the boost templates (range_iterator, range_const_iterator, and possibly also range_value) to only have a nested ::type when BoundedRange<X> is true (or BoundedRange<X const> in the case of range_const_iterator).

tonyelewis commented 7 years ago

Thanks for the reply - that makes sense. Sorry for the slow response. Just looking at it now...

I'm implementing the conditionally present ::type by using partial template specialisation, creating a provide_type_if type:

namespace ranges { inline namespace v3 { namespace detail {
    template <typename T, bool B>
    struct provide_type_if {};

    template <typename T>
    struct provide_type_if<T, true> {
        using type = T;
    };
} } }

...and then making the Boost hooks inherit from that like :

template <typename... Ts>
struct range_mutable_iterator< view_name< Ts... >, void>
    : public ::ranges::v3::detail::provide_type_if<
        ::ranges::range_iterator_t<       view_name< Ts... > >,
        static_cast<bool>( ::ranges::BoundedRange<       view_name< Ts... > >() )
    > {};

Does that look OK to you?

Is that the right sort of syntax to get a compile-time bool from BoundedRange?

Using that approach, I seem to be getting that remove_if_view is a BoundedRange because the following code prints true :

#include <range/v3/all.hpp>

#include <boost/optional.hpp>

#include <iostream>
#include <vector>

int main() {
    const std::vector< boost::optional< int > > &a = { 1, 2, 3, 4, 5 };
    auto b = a  | ranges::view::remove_if( [] (const boost::optional<int> &x) { return ! x;     } );

    std::cerr << std::boolalpha << static_cast<bool>( ranges::BoundedRange< decltype( b ) >::value ) << "\n";
}

Is that right?

Thanks very much.

ericniebler commented 7 years ago

Use SFINAE in the template parameter this (untested):

template <typename... Ts>
struct range_mutable_iterator<
    view_name< Ts... >,
    ::meta::if_c<(bool) ::ranges::BoundedRange< view_name< Ts... > >() > >
{
    using type = ::ranges::range_iterator_t< view_name< Ts... > >;
};

Then for range_const_iterator, you'll need to test whether view_name<...> const is a BoundedRange, like:

template <typename... Ts>
struct range_const_iterator<
    view_name< Ts... >,
    ::meta::if_c<(bool) ::ranges::BoundedRange< view_name< Ts... > const >() > >
{
    using type = ::ranges::range_iterator_t< view_name< Ts... > const >;
};

Not sure if you need to do anything about range_value.

tonyelewis commented 7 years ago

Thanks very much for this.

It's still not working but from what I tell, this just seems to be because remove_if_view seems to pass BoundedRange. Does that sound plausible? Does it sound correct?

Thanks.

ericniebler commented 7 years ago

I'll have to get back to you. Casey and I currently scrambling to get an updated Ranges TS ready for the post-meeting mailing. Thanks for your work on this.

tonyelewis commented 7 years ago

NP. Good luck with the work on the TS - really important and valuable stuff.

A bit more info for when things are a bit less hectic at your end...

From what I can tell:

I'll look into it further. My first impression is that this line in Boost.Range's SinglePassRangeConcept should be getting its const_iterator via something like range_const_iterator<R>, not by assuming that the const_iterator of R is range_iterator<const R>. Does that sound plausible?


Just FYI (in case it crops up again in this issue), the begin() / end() type I'm seeing from view::remove_if is:

basic_iterator<
  adaptor_cursor<
    std::__wrap_iter<int *>,
    remove_if_view<
      iterator_range<std::__wrap_iter<int *>, std::__wrap_iter<int *> >,
      (lambda at br.cpp:9:24)
    >::adaptor
  >,
  adaptor_cursor<
    std::__wrap_iter<int *>,
    remove_if_view<
      iterator_range<std::__wrap_iter<int *>, std::__wrap_iter<int *> >,
      (lambda at br.cpp:9:24)
    >::adaptor
  >
>
tonyelewis commented 7 years ago

Same problem; different :coffee: shop; different part of London.

Right, I've got something that fixes the original compile error by demanding that the view type remains a BoundedRange after being transformed by each of add_const and remove_const .

I've submitted P-R #503. Let me know your thoughts.

ericniebler commented 7 years ago

The problem is due to a bug in Boost.Range. See this PR, which is the correct fix: boostorg/range#47.

The question is how to work around the bug from our end. Your suggested fix is a bit of an ugly hack that makes Boost.Range pretty much unusable for a great many of range-v3's views. Now that I understand the problem better, let me think on it.

tonyelewis commented 7 years ago

Sorry for the slow response. Yes - this all looks great and is working for me. Thanks very much for figuring this out and fixing.