Closed tonyelewis closed 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
).
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.
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
.
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.
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.
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:
view::remove_if
passes BoundedRange
view::remove_if
's begin()
/ end()
types genuinely are the sameview::remove_if
is the other difference you mentioned between Boost.Range / range-v3 range concepts, ie that though view::remove_if
is a range, const view::remove_if
isn't.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
>
>
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.
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.
Sorry for the slow response. Yes - this all looks great and is working for me. Thanks very much for figuring this out and fixing.
The following fails to compile under both GCC and Clang (errors attached):
Interestingly the problem disappears if I simplify to
int
rather thanoptional<int>
: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-memberbegin
of theconst 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 tweakRANGES_SATISFY_BOOST_RANGE()
to drop the const.Start of GCC errors:
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