https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94973
Bug ID: 94973 Summary: compile error when trying to use pointer-to-member function as invokable projection to ranges::find() Product: gcc Version: 9.3.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: libstdc++ Assignee: unassigned at gcc dot gnu.org Reporter: db0451 at gmail dot com Target Milestone: --- `range-v3` has the concept of "invocable projections", i.e. simple transformations that can be applied as predicates to its algorithms. Pointer-to-member-functions should be included and mean 'get the result of calling that on the current element'. However, it seems that invoking a pointer-to-member-function in g++ (but NOT clang++) causes the build to fail. Given the code, compiled with `g++ -std=c++17` against `ericniebler/range-v3` release `range-v3-0.10.0`, using `g++.exe (Rev2, Built by MSYS2 project) 9.3.0`: ```cpp #include <range/v3/algorithm/find.hpp> #include <vector> auto main() -> int { struct S { int i{}; auto get_i() const { return i; } }; auto const ss = std::vector<S>(10); ranges::find(ss, 1, &S::get_i); return 0; } ``` I get a spew of errors: ```none test.cpp: In function 'int main()': test.cpp:14:31: error: no match for call to '(const ranges::find_fn) (const std::vector<main()::S>&, int, int (main()::S::*)() const)' 14 | ranges::find(ss, 1, &S::get_i); | ^ In file included from FOO/include/range-v3/range/v3/range_fwd.hpp:24, from FOO/include/range-v3/range/v3/algorithm/find.hpp:18, from test.cpp:1: FOO/include/range-v3/range/v3/detail/config.hpp:618:27: note: candidate: 'template<class I, class S, class V, class P> constexpr concepts::return_t<I, typename std::enable_if<(((input_iterator<I> && sentinel_for<S, I>) && indirect_relation<ranges::equal_to, typename ranges::detail::select_projected_<P>::apply<I>, const V*>) && concepts::detail::CPP_true(concepts::detail::Nil{})), void>::type> ranges::find_fn::operator()(I, S, const V&, P) const' 618 | #define RANGES_FUNC(NAME) operator() RANGES_FUNC_CONST_ /**/ | ^~~~~~~~ FOO/include/range-v3/range/v3/algorithm/find.hpp:47:24: note: in expansion of macro 'RANGES_FUNC' 47 | constexpr auto RANGES_FUNC(find)(I first, S last, V const & val, P proj = P{}) | ^~~~~~~~~~~ FOO/include/range-v3/range/v3/detail/config.hpp:618:27: note: template argument deduction/substitution failed: 618 | #define RANGES_FUNC(NAME) operator() RANGES_FUNC_CONST_ /**/ | ^~~~~~~~ FOO/include/range-v3/range/v3/algorithm/find.hpp:47:24: note: in expansion of macro 'RANGES_FUNC' 47 | constexpr auto RANGES_FUNC(find)(I first, S last, V const & val, P proj = P{}) | ^~~~~~~~~~~ In file included from FOO/include/range-v3/range/v3/iterator/access.hpp:22, from FOO/include/range-v3/range/v3/iterator/concepts.hpp:30, from FOO/include/range-v3/range/v3/algorithm/find.hpp:22, from test.cpp:1: FOO/include/range-v3/std/detail/associated_types.hpp: In substitution of 'template<bool B, class T> using enable_if_t = typename ranges::detail::enable_if::apply<T> [with bool B = ranges::readable<std::vector<main()::S> >; T = std::vector<main()::S>]': FOO/include/range-v3/range/v3/iterator/concepts.hpp:561:19: required by substitution of 'template<class I> using apply = ranges::detail::enable_if_t<(bool)(readable<I>), I> [with I = std::vector<main()::S>]' FOO/include/range-v3/range/v3/algorithm/find.hpp:48:15: required by substitution of 'template<class I, class S, class V, class P> constexpr concepts::return_t<I, typename std::enable_if<(((input_iterator<I> && sentinel_for<S, I>) && indirect_relation<ranges::equal_to, typename ranges::detail::select_projected_<P>::apply<I>, const V*>) && concepts::detail::CPP_true(concepts::detail::Nil{})), void>::type> ranges::find_fn::operator()(I, S, const V&, P) const [with I = std::vector<main()::S>; S = int; V = int (main()::S::*)() const; P = ranges::identity]' test.cpp:14:31: required from here FOO/include/range-v3/std/detail/associated_types.hpp:73:15: error: no class template named 'apply' in 'struct ranges::detail::enable_if<false>' 73 | using enable_if_t = typename enable_if<B>::template apply<T>; | ^~~~~~~~~~~ In file included from FOO/include/range-v3/range/v3/range_fwd.hpp:24, from FOO/include/range-v3/range/v3/algorithm/find.hpp:18, from test.cpp:1: FOO/include/range-v3/range/v3/detail/config.hpp:618:27: note: candidate: 'template<class Rng, class V, class P> constexpr concepts::return_t<typename ranges::detail::if_then<forwarding_range_<R> >::apply<decltype (ranges::_::begin(declval<Rng&>())), ranges::dangling>, typename std::enable_if<((input_range<Rng> && indirect_relation<ranges::equal_to, typename ranges::detail::select_projected_<P1>::apply<decltype (ranges::_::begin(declval<Rng&>()))>, const V*>) && concepts::detail::CPP_true(concepts::detail::Nil{})), void>::type> ranges::find_fn::operator()(Rng&&, const V&, P) const' 618 | #define RANGES_FUNC(NAME) operator() RANGES_FUNC_CONST_ /**/ | ^~~~~~~~ FOO/include/range-v3/range/v3/algorithm/find.hpp:60:24: note: in expansion of macro 'RANGES_FUNC' 60 | constexpr auto RANGES_FUNC(find)(Rng && rng, V const & val, P proj = P{}) | ^~~~~~~~~~~ FOO/include/range-v3/range/v3/detail/config.hpp:618:27: note: template argument deduction/substitution failed: 618 | #define RANGES_FUNC(NAME) operator() RANGES_FUNC_CONST_ /**/ | ^~~~~~~~ FOO/include/range-v3/range/v3/algorithm/find.hpp:60:24: note: in expansion of macro 'RANGES_FUNC' 60 | constexpr auto RANGES_FUNC(find)(Rng && rng, V const & val, P proj = P{}) | ^~~~~~~~~~~ In file included from FOO/include/range-v3/range/v3/iterator/access.hpp:22, from FOO/include/range-v3/range/v3/iterator/concepts.hpp:30, from FOO/include/range-v3/range/v3/algorithm/find.hpp:22, from test.cpp:1: FOO/include/range-v3/std/detail/associated_types.hpp: In substitution of 'template<bool B, class T> using enable_if_t = typename ranges::detail::enable_if::apply<T> [with bool B = ranges::indirectly_regular_unary_invocable<int (main()::S::*)() const, __gnu_cxx::__normal_iterator<const main()::S*, std::vector<main()::S> > >; T = ranges::detail::projected_<__gnu_cxx::__normal_iterator<const main()::S*, std::vector<main()::S> >, int (main()::S::*)() const>]': FOO/include/range-v3/range/v3/iterator/concepts.hpp:552:19: required by substitution of 'template<class Proj> template<class I> using apply = ranges::detail::enable_if_t<(bool)(indirectly_regular_unary_invocable<Proj, I>), ranges::detail::projected_<I, Proj> > [with I = __gnu_cxx::__normal_iterator<const main()::S*, std::vector<main()::S> >; Proj = int (main()::S::*)() const]' FOO/include/range-v3/range/v3/algorithm/find.hpp:61:15: required by substitution of 'template<class Rng, class V, class P> constexpr concepts::return_t<typename ranges::detail::if_then<forwarding_range_<R> >::apply<decltype (ranges::_::begin(declval<Rng&>())), ranges::dangling>, typename std::enable_if<((input_range<Rng> && indirect_relation<ranges::equal_to, typename ranges::detail::select_projected_<P1>::apply<decltype (ranges::_::begin(declval<Rng&>()))>, const V*>) && concepts::detail::CPP_true(concepts::detail::Nil{})), void>::type> ranges::find_fn::operator()(Rng&&, const V&, P) const [with Rng = const std::vector<main()::S>&; V = int; P = int (main()::S::*)() const]' test.cpp:14:31: required from here FOO/include/range-v3/std/detail/associated_types.hpp:73:15: error: no class template named 'apply' in 'struct ranges::detail::enable_if<false>' 73 | using enable_if_t = typename enable_if<B>::template apply<T>; | ^~~~~~~~~~~ shell returned 1 ``` * Making the projection a lambda works but seems wasted typing. * Referring directly to the data member works but is not possible if it should be encapsulated behind a const getter, transformer, etc. * `clang++` (also on MSYS2) **does** work here. So I guess this must be a bug in `g++`.