ошибка: нет соответствия для «operator=» (типы операндов — «const XXX» и «std::remove_reference‹const XXX&›::type» {aka «const XXX»})

Я попытался использовать итератор диапазона повышения для реализации LINQ. Когда дело доходит до различия с данным предикатом, у меня возникают некоторые проблемы. Чтобы описать мою проблему прямо и просто, я написал минимальный пример:

// test.cc
#include <algorithm>
#include <boost/range.hpp>
#include <boost/range/adaptors.hpp>
#include <boost/range/algorithm.hpp>
#include <iostream>
#include <vector>
using namespace std;

template <typename R>
class Linq {
 private:
  R range_;

 public:
  typedef typename R::value_type value_type;
  Linq(R& range) : range_(range) {}
  Linq(const R& range) : range_(range) {}
  ~Linq() = default;
  template <typename F>
  auto Distinct(const F& f) {
    auto ur = boost::range::unique(range_, f);
    return Linq(ur);
  }

  auto Distinct() -> Linq<boost::range_detail::uniqued_range<R>> {
    boost::range_detail::uniqued_range<R> ur =
        range_ | boost::adaptors::uniqued;
    return Linq<boost::range_detail::uniqued_range<R>>(ur);
  }
  template <typename F>
  void for_each(const F& f) {
    std::for_each(std::begin(range_), std::end(range_), f);
  }
};

template <template <typename T> class linq_range_tmpl, typename R>
using linq_range_private =
    linq_range_tmpl<decltype(std::begin(std::declval<R>()))>;

template <typename R>
using linq_range_iterator = linq_range_private<boost::iterator_range, R>;

// All the Linq object should be created by From function
template <typename R>
Linq<linq_range_iterator<R>> From(const R& range) {
  linq_range_iterator<R> ir(range);
  return Linq<decltype(ir)>(ir);
}

int main() {
  std::vector<string> vec = {"Hello", "Hello", "Phoenix", "Jack", "Rose"};
  auto filter = [](const string& str1, const string& str2) {
    return str1.length() == str2.length();
  };
  auto Printer = [](const string& str) { cout << str << " "; };

  From(vec).Distinct().for_each(Printer);
  cout << endl;

  //From(vec).Distinct(filter).for_each(Printer);   // this statement will launch a compile error
  cout << endl;
}

Кстати, моя операционная среда выглядит следующим образом:

  • ОС Ubuntu-20.04 LTS
  • Компилятор gcc-9.3.0
  • Повышение версии 1.71

Как видите, когда я добавляю оператор From(vec).Distinct(filter).for_each(Printer) в комментарий, все работает отлично. Результат выполнения:

$ Hello Phoenix Jack Rose

Результат метода distint с заданным предикатом должен выглядеть так:

$ Hello Phoenix Jack

Но если я оставлю это утверждение без комментариев, я получу много сообщений об ошибках:

$ g++ test.cc -std=c++17

In file included from /usr/include/c++/9/algorithm:62,
                 from test.cc:1:
/usr/include/c++/9/bits/stl_algo.h: In instantiation of ‘_ForwardIterator std::__unique(_ForwardIterator, _ForwardIterator, _BinaryPredicate) [with _ForwardIterator = __gnu_cxx::__normal_iterator<const std::__cxx11::basic_string<char>*, std::vector<std::__cxx11::basic_string<char> > >; _BinaryPredicate = __gnu_cxx::__ops::_Iter_comp_iter<main()::<lambda(const string&, const string&)> >]’:
/usr/include/c++/9/bits/stl_algo.h:1036:27:   required from ‘_FIter std::unique(_FIter, _FIter, _BinaryPredicate) [with _FIter = __gnu_cxx::__normal_iterator<const std::__cxx11::basic_string<char>*, std::vector<std::__cxx11::basic_string<char> > >; _BinaryPredicate = main()::<lambda(const string&, const string&)>]’
/usr/include/boost/range/algorithm/unique.hpp:56:25:   required from ‘typename boost::range_return<ForwardRange, re>::type boost::range::unique(ForwardRange&, BinaryPredicate) [with boost::range_return_value re = boost::return_begin_found; ForwardRange = boost::iterator_range<__gnu_cxx::__normal_iterator<const std::__cxx11::basic_string<char>*, std::vector<std::__cxx11::basic_string<char> > > >; BinaryPredicate = main()::<lambda(const string&, const string&)>; typename boost::range_return<ForwardRange, re>::type = boost::iterator_range<__gnu_cxx::__normal_iterator<const std::__cxx11::basic_string<char>*, std::vector<std::__cxx11::basic_string<char> > > >]’
/usr/include/boost/range/algorithm/unique.hpp:92:54:   required from ‘typename boost::range_return<SinglePassRange, boost::return_begin_found>::type boost::range::unique(ForwardRange&, BinaryPredicate) [with ForwardRange = boost::iterator_range<__gnu_cxx::__normal_iterator<const std::__cxx11::basic_string<char>*, std::vector<std::__cxx11::basic_string<char> > > >; BinaryPredicate = main()::<lambda(const string&, const string&)>; typename boost::range_return<SinglePassRange, boost::return_begin_found>::type = boost::iterator_range<__gnu_cxx::__normal_iterator<const std::__cxx11::basic_string<char>*, std::vector<std::__cxx11::basic_string<char> > > >]’
test.cc:21:35:   required from ‘auto Linq<R>::Distinct(const F&) [with F = main()::<lambda(const string&, const string&)>; R = boost::iterator_range<__gnu_cxx::__normal_iterator<const std::__cxx11::basic_string<char>*, std::vector<std::__cxx11::basic_string<char> > > >]’
test.cc:59:28:   required from here
/usr/include/c++/9/bits/stl_algo.h:975:14: error: no match for ‘operator=’ (operand types are ‘const std::__cxx11::basic_string<char>’ and ‘std::remove_reference<const std::__cxx11::basic_string<char>&>::type’ {aka ‘const std::__cxx11::basic_string<char>’})
  975 |    *++__dest = _GLIBCXX_MOVE(*__first);
      |              ^
In file included from /usr/include/c++/9/string:55,
                 from /usr/include/c++/9/stdexcept:39,
                 from /usr/include/c++/9/array:39,
                 from /usr/include/c++/9/tuple:39,
                 from /usr/include/c++/9/functional:54,
                 from /usr/include/c++/9/pstl/glue_algorithm_defs.h:13,
                 from /usr/include/c++/9/algorithm:71,
                 from test.cc:1:
/usr/include/c++/9/bits/basic_string.h:665:7: note: candidate: ‘std::__cxx11::basic_string<_CharT, _Traits, _Alloc>& std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::operator=(const std::__cxx11::basic_string<_CharT, _Traits, _Alloc>&) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]’ <near match>
  665 |       operator=(const basic_string& __str)
      |       ^~~~~~~~
/usr/include/c++/9/bits/basic_string.h:665:7: note:   passing ‘const std::__cxx11::basic_string<char>*’ as ‘this’ argument discards qualifiers
/usr/include/c++/9/bits/basic_string.h:732:7: note: candidate: ‘std::__cxx11::basic_string<_CharT, _Traits, _Alloc>& std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::operator=(std::__cxx11::basic_string<_CharT, _Traits, _Alloc>&&) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]’ <near match>
  732 |       operator=(basic_string&& __str)
      |       ^~~~~~~~
/usr/include/c++/9/bits/basic_string.h:732:7: note:   conversion of argument 1 would be ill-formed:
In file included from /usr/include/c++/9/algorithm:62,
                 from test.cc:1:
/usr/include/c++/9/bits/stl_algo.h:975:14: error: binding reference of type ‘std::__cxx11::basic_string<char>&&’ to ‘std::remove_reference<const std::__cxx11::basic_string<char>&>::type’ {aka ‘const std::__cxx11::basic_string<char>’} discards qualifiers
  975 |    *++__dest = _GLIBCXX_MOVE(*__first);
      |              ^
In file included from /usr/include/c++/9/string:55,
                 from /usr/include/c++/9/stdexcept:39,
                 from /usr/include/c++/9/array:39,
                 from /usr/include/c++/9/tuple:39,
                 from /usr/include/c++/9/functional:54,
                 from /usr/include/c++/9/pstl/glue_algorithm_defs.h:13,
                 from /usr/include/c++/9/algorithm:71,
                 from test.cc:1:
/usr/include/c++/9/bits/basic_string.h:704:7: note: candidate: ‘std::__cxx11::basic_string<_CharT, _Traits, _Alloc>& std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::operator=(const _CharT*) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]’
  704 |       operator=(const _CharT* __s)
      |       ^~~~~~~~
/usr/include/c++/9/bits/basic_string.h:704:31: note:   no known conversion for argument 1 from ‘std::remove_reference<const std::__cxx11::basic_string<char>&>::type’ {aka ‘const std::__cxx11::basic_string<char>’} to ‘const char*’
  704 |       operator=(const _CharT* __s)
      |                 ~~~~~~~~~~~~~~^~~
/usr/include/c++/9/bits/basic_string.h:715:7: note: candidate: ‘std::__cxx11::basic_string<_CharT, _Traits, _Alloc>& std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::operator=(_CharT) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]’
  715 |       operator=(_CharT __c)
      |       ^~~~~~~~
/usr/include/c++/9/bits/basic_string.h:715:24: note:   no known conversion for argument 1 from ‘std::remove_reference<const std::__cxx11::basic_string<char>&>::type’ {aka ‘const std::__cxx11::basic_string<char>’} to ‘char’
  715 |       operator=(_CharT __c)
      |                 ~~~~~~~^~~
/usr/include/c++/9/bits/basic_string.h:795:7: note: candidate: ‘std::__cxx11::basic_string<_CharT, _Traits, _Alloc>& std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::operator=(std::initializer_list<_Tp>) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]’
  795 |       operator=(initializer_list<_CharT> __l)
      |       ^~~~~~~~
/usr/include/c++/9/bits/basic_string.h:795:42: note:   no known conversion for argument 1 from ‘std::remove_reference<const std::__cxx11::basic_string<char>&>::type’ {aka ‘const std::__cxx11::basic_string<char>’} to ‘std::initializer_list<char>’
  795 |       operator=(initializer_list<_CharT> __l)
      |                 ~~~~~~~~~~~~~~~~~~~~~~~~~^~~
/usr/include/c++/9/bits/basic_string.h:809:8: note: candidate: ‘template<class _Tp> std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::_If_sv<_Tp, std::__cxx11::basic_string<_CharT, _Traits, _Alloc>&> std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::operator=(const _Tp&) [with _Tp = _Tp; _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]’
  809 |        operator=(const _Tp& __svt)
      |        ^~~~~~~~
/usr/include/c++/9/bits/basic_string.h:809:8: note:   template argument deduction/substitution failed:
In file included from /usr/include/c++/9/bits/move.h:55,
                 from /usr/include/c++/9/bits/stl_pair.h:59,
                 from /usr/include/c++/9/utility:70,
                 from /usr/include/c++/9/algorithm:60,
                 from test.cc:1:
/usr/include/c++/9/type_traits: In substitution of ‘template<bool _Cond, class _Tp> using enable_if_t = typename std::enable_if::type [with bool _Cond = std::integral_constant<bool, false>::value; _Tp = std::__cxx11::basic_string<char>&]’:
/usr/include/c++/9/bits/basic_string.h:117:8:   required by substitution of ‘template<class _CharT, class _Traits, class _Alloc> template<class _Tp, class _Res> using _If_sv = std::enable_if_t<std::__and_<std::is_convertible<const _Tp&, std::basic_string_view<_CharT, _Traits> >, std::__not_<std::is_convertible<const _Tp*, const std::__cxx11::basic_string<_CharT, _Traits, _Alloc>*> >, std::__not_<std::is_convertible<const _Tp&, const _CharT*> > >::value, _Res> [with _Tp = std::__cxx11::basic_string<char>; _Res = std::__cxx11::basic_string<char>&; _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]’
/usr/include/c++/9/bits/basic_string.h:809:8:   required by substitution of ‘template<class _Tp> std::__cxx11::basic_string<char>::_If_sv<_Tp, std::__cxx11::basic_string<char>&> std::__cxx11::basic_string<char>::operator=<_Tp>(const _Tp&) [with _Tp = std::__cxx11::basic_string<char>]’
/usr/include/c++/9/bits/stl_algo.h:975:14:   required from ‘_ForwardIterator std::__unique(_ForwardIterator, _ForwardIterator, _BinaryPredicate) [with _ForwardIterator = __gnu_cxx::__normal_iterator<const std::__cxx11::basic_string<char>*, std::vector<std::__cxx11::basic_string<char> > >; _BinaryPredicate = __gnu_cxx::__ops::_Iter_comp_iter<main()::<lambda(const string&, const string&)> >]’
/usr/include/c++/9/bits/stl_algo.h:1036:27:   required from ‘_FIter std::unique(_FIter, _FIter, _BinaryPredicate) [with _FIter = __gnu_cxx::__normal_iterator<const std::__cxx11::basic_string<char>*, std::vector<std::__cxx11::basic_string<char> > >; _BinaryPredicate = main()::<lambda(const string&, const string&)>]’
/usr/include/boost/range/algorithm/unique.hpp:56:25:   required from ‘typename boost::range_return<ForwardRange, re>::type boost::range::unique(ForwardRange&, BinaryPredicate) [with boost::range_return_value re = boost::return_begin_found; ForwardRange = boost::iterator_range<__gnu_cxx::__normal_iterator<const std::__cxx11::basic_string<char>*, std::vector<std::__cxx11::basic_string<char> > > >; BinaryPredicate = main()::<lambda(const string&, const string&)>; typename boost::range_return<ForwardRange, re>::type = boost::iterator_range<__gnu_cxx::__normal_iterator<const std::__cxx11::basic_string<char>*, std::vector<std::__cxx11::basic_string<char> > > >]’
/usr/include/boost/range/algorithm/unique.hpp:92:54:   required from ‘typename boost::range_return<SinglePassRange, boost::return_begin_found>::type boost::range::unique(ForwardRange&, BinaryPredicate) [with ForwardRange = boost::iterator_range<__gnu_cxx::__normal_iterator<const std::__cxx11::basic_string<char>*, std::vector<std::__cxx11::basic_string<char> > > >; BinaryPredicate = main()::<lambda(const string&, const string&)>; typename boost::range_return<SinglePassRange, boost::return_begin_found>::type = boost::iterator_range<__gnu_cxx::__normal_iterator<const std::__cxx11::basic_string<char>*, std::vector<std::__cxx11::basic_string<char> > > >]’
test.cc:21:35:   required from ‘auto Linq<R>::Distinct(const F&) [with F = main()::<lambda(const string&, const string&)>; R = boost::iterator_range<__gnu_cxx::__normal_iterator<const std::__cxx11::basic_string<char>*, std::vector<std::__cxx11::basic_string<char> > > >]’
test.cc:59:28:   required from here
/usr/include/c++/9/type_traits:2385:11: error: no type named ‘type’ in ‘struct std::enable_if<false, std::__cxx11::basic_string<char>&>’
 2385 |     using enable_if_t = typename enable_if<_Cond, _Tp>::type;

Меня беспокоит этот вопрос уже несколько дней. Я сделал все возможное, чтобы решить эту проблему, но это все еще не работает. Я исчерпал свои трюки. Может ли кто-нибудь дать мне подсказку, чтобы решить эту проблему?


person Phoenix Chao    schedule 15.01.2021    source источник


Ответы (1)


    auto ur = boost::range::unique(range_, f);

пытается изменить range_ на месте, но его элементы доступны только для чтения (const). Адаптер uniqued НЕ делает этого. Вероятно, вы случайно их перепутали. Судя по названиям вещей, это, казалось бы, лучше подходит:

  template <typename F>
  auto Distinct(F const& f) {
    auto ur = range_ 
        | boost::adaptors::filtered(f)
        | boost::adaptors::uniqued;
    return Linq<decltype(ur)>(ur);
  }

Теперь «фильтр» — это неправильное название, потому что для этого потребуется предикат. Что вы имели в виду, может быть comparator? Тем не мение:

В общем, кажется, что вы делаете слишком много работы, чтобы просто получить синтаксический сахар для существующих библиотек Range.

См. также Есть ли библиотека LINQ для C++? для некоторых дизайнерских мыслей об этой идее.

person sehe    schedule 15.01.2021