Reputation: 28490
Here is the code:
#include <boost/range/iterator_range.hpp>
#include <functional>
#include <list>
#include <range/v3/range/conversion.hpp>
#include <range/v3/view/transform.hpp>
#include <vector>
using namespace ranges;
using namespace ranges::views;
int main()
{
std::list<int> v;
auto r = boost::make_iterator_range(v);
auto w = r
| transform([](auto x){ return x; })
| to_vector;
}
It does not compile for c++20, the error being copied two code snippets below.
Either of these actions makes it compile
std::list
to std::vector
,r
const
,What is the correct behavior, Clang's or GCC's, according to c++20 and c++17?
Here are the variations described above on Compiler Explorer.
I'm more and more convinced this is a bug in GCC. I've been told it's not, but I can't really get my head around the arguments listed from those answers.
I've stripped an example down to the following:
#include <boost/range/iterator_range_core.hpp>
#include <list>
#include <range/v3/view/ref.hpp>
int main() {
std::list<int> l;
using Foo = const ranges::ref_view<boost::iterator_range<decltype(l.begin())>>&;
ranges::_size_::has_non_member_size<Foo>;
}
which
-std=c++20
compiles with GCC <= 10.5 and fails to compile with GCC >= 11.1,-std=c++17
compiles in both cases.The error starts like this, and it seems to refer to a concept that requires itself (see the first link above for the full error):
In file included from /opt/compiler-explorer/libs/rangesv3/trunk/include/range/v3/view/ref.hpp:17,
from <source>:3:
/opt/compiler-explorer/libs/rangesv3/trunk/include/range/v3/range/traits.hpp: In substitution of 'template<class R> requires (!(has_member_size<R>) || (disable_sized_range<typename std::remove_cv<typename std::remove_reference<_Tp>::type>::type>)) && (!(has_non_member_size<R>) || (disable_sized_range<typename std::remove_cv<typename std::remove_reference<_Tp>::type>::type>)) && (forward_iterator<decltype({}(static_cast<R&& (*)()noexcept (true)>(nullptr)()))>) && (sized_sentinel_for<decltype({}(static_cast<R&& (*)()noexcept (true)>(nullptr)())), decltype({}(static_cast<R&& (*)()noexcept (true)>(nullptr)()))>) constexpr ranges::_size_::fn::_result_t<R> ranges::_size_::fn::operator()(R&&) const [with R = const ranges::ref_view<boost::iterator_range<std::_List_iterator<int> > >&]':
/opt/compiler-explorer/libs/rangesv3/trunk/include/range/v3/range/traits.hpp:76:47: required by substitution of 'template<class Rng> using range_size_t = decltype (ranges::_::size(declval<Rng&>())) [with Rng = const ranges::ref_view<boost::iterator_range<std::_List_iterator<int> > >]'
/opt/compiler-explorer/libs/rangesv3/trunk/include/meta/meta_fwd.hpp:286:18: required by substitution of 'template<template<class ...> class C, class ... Ts> requires valid<C, Ts ...> struct meta::detail::defer_<C, Ts ...> [with C = ranges::range_size_t; Ts = {const ranges::ref_view<boost::iterator_range<std::_List_iterator<int> > >}]'
/opt/compiler-explorer/libs/rangesv3/trunk/include/meta/meta.hpp:788:12: required from 'struct meta::defer<ranges::range_size_t, const ranges::ref_view<boost::iterator_range<std::_List_iterator<int> > > >'
/opt/compiler-explorer/libs/rangesv3/trunk/include/range/v3/view/ref.hpp:121:1: required from 'struct boost::range_size<const ranges::ref_view<boost::iterator_range<std::_List_iterator<int> > > >'
/opt/compiler-explorer/libs/boost_1_85_0/boost/range/size.hpp:55:5: required by substitution of 'template<class SinglePassRange> typename boost::range_size<const SinglePassRange>::type boost::size(const SinglePassRange&) [with SinglePassRange = ranges::ref_view<boost::iterator_range<std::_List_iterator<int> > >]'
/opt/compiler-explorer/libs/rangesv3/trunk/include/range/v3/range/primitives.hpp:63:9: required from here
/opt/compiler-explorer/libs/rangesv3/trunk/include/range/v3/range/primitives.hpp:63:9: required for the satisfaction of 'has_non_member_size_requires_<T>' [with T = const ranges::ref_view<boost::iterator_range<std::_List_iterator<int> > >&]
/opt/compiler-explorer/libs/rangesv3/trunk/include/range/v3/range/primitives.hpp:63:9: in requirements with 'T&& t' [with T = const ranges::ref_view<boost::iterator_range<std::_List_iterator<int> > >&]
/opt/compiler-explorer/libs/rangesv3/trunk/include/range/v3/range/primitives.hpp:63:9: error: satisfaction of atomic constraint 'requires(T&& t) {ranges::_size_::size((T&&(t)));} [with T = T]' depends on itself
63 | CPP_requires(has_non_member_size_,
| ^
Some observations:
const
from the definition of the Foo
alias fixes the compilation failure;const
and changing std::list
to std::vector
also fixes the compilation failure;<range/v3/range/primitives.hpp>
and <concepts/concepts.hpp>
;
ranges::_size_::has_non_member_size<Foo>;
resolves to ranges::_size_::has_non_member_size_requires_<Foo>;
, and clangd tells me, if I understand it (which I don't think I do!), that is equivalent to
template <typename T>
concept has_non_member_size_requires_ = requires(T &&t) { size((T &&)t); }
but if I just write such a concept before main
and substitute it into the last line of the original snippet, I don't get a compilation failure.Can somebody enlighten me on what's happening?
Upvotes: 4
Views: 140