ошибка компиляции при попытке использовать функцию указателя на член в качестве проекции на диапазоны :: find () - PullRequest
0 голосов
/ 06 мая 2020

Я хочу найти в диапазоне ввода элемент, который имеет определенное значение в члене с помощью средства доступа.

range-v3 документация ... thin , но есть источники, такие как этот ответ от AFAIK, 2 основных range-v3 разработчика указывают, что такая вещь должна просто работать, хотя с sort не find.

Учитывая код, скомпилированный с g++ -std=c++17 против ericniebler/range-v3 release range-v3-0.10.0, используя g++.exe (Rev2, Built by MSYS2 project) 9.3.0:

#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;
}

Я получаю массу ошибок:

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

Создание проекции лямбда ...

ranges::find( ss, 1, [](auto const& s){ return s.get_i(); } );

... работает, но набирает напрасно.


Обращение непосредственно к элементу данных ...

ranges::find(ss, 1, &S::i);

. ..работает, но невозможно, если его следует инкапсулировать за константным геттером, трансформатором и т. д. c.


Что я делаю не так? Могу ли я использовать в качестве проекции указатель на член- функцию ? Это предназначено?


Edit : clang++ (также на MSYS2) здесь работает . Думаю, это ошибка в g++. Перейти в Bugzilla I go ... изменить: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94973

1 Ответ

0 голосов
/ 07 мая 2020

Это вызвано тем, что G CC на Windows по умолчанию имеет значение -fms-extensions для совместимости с компиляторами Microsoft, и это вызывает нестандартное расширение, которое вводит двусмысленность между указателями на данные-члены и записанными функциями. как instance.*member.

Мы можем передать -fno-ms-extensions, чтобы остановить это и успешно скомпилировать такой код, пока G CC не удалит это конкретное расширение, которое в настоящее время кажется ненужным и бесполезным.

Jonathan ответил на это мой G CC ошибка 94973 :


Jonathan Wakely 2020-05-06 16:26:58 UTC

Aha, the same problem happens on linux if I compile with -fms-extensions

This is the old MS extension that causes x.*f to be accepted when f is a pointer to member function, which should only be valid when used as (x.*f)().

That causes ranges::invoke to think that the projection is a pointer to data member, when actually it's a pointer to member function.

See also PR 94771 comment 4.

Jason, do we want to disable that extension in SFINAE contexts?

Jonathan Wakely 2020-05-06 16:47:42 UTC

They're on by default for mingw, for compatibility with the MS compiler (but in this case it seems the relevant extension is ancient history).
...