error: no match for ‘operator=’ (operand types are ‘const XXX’ and ‘std::remove_reference<const XXX&>::type’ {aka ‘const XXX’})

error: no match for ‘operator=’ (operand types are ‘const XXX’ and ‘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;
}

顺便说一句,我的运行环境如下:

如您所见,当我将语句 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;

我被这个问题困扰了好几天。我尽我所能来解决这个问题,但它仍然不起作用。我已经用尽了我的技巧。谁能给我一些提示来解决它?

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

现在,'filter' 是用词不当,因为它需要谓词。你的意思可能是comparator?然而:

总而言之,您似乎只为现有 Range 库获取一些语法糖就做了太多工作。

另请参阅 Is there a LINQ library for C++? 了解有关此想法的一些设计想法。