扩展 boost::filtered 的迭代器以支持 operator+ 重载

Extending iterator of boost::filtered to support operator+ overload

我想向 boost::filter_iterator 添加一个 operator+ 重载,如下例所示。但是,我在将模板参数解析为 operator+ 重载函数时遇到错误。

#include <iostream>
#include <vector>
#include <boost/range/adaptor/filtered.hpp>

 template <typename TPredicate, typename TRange> 
class Filtered_Range : public boost::filtered_range<TPredicate, TRange>
   {
     public:
  
       Filtered_Range(TPredicate Predicate, TRange& Range) : boost::filtered_range<TPredicate, TRange>(Predicate, Range) {}
  
       size_t size() const { return std::distance(this->begin(), this->end()); }
  
       auto operator[](size_t Index) const
       {
           assert(Index < this->size());
           auto It = this->begin();
           std::advance(It, Index);
           return *It;
       }
       
   };

template<typename TPredicate, typename TRange> 
typename Filtered_Range<TPredicate, TRange>::filter_iterator&  
operator+(typename 
Filtered_Range<TPredicate, TRange>::filter_iterator& f, int32_t x  ) {
    std::cout << "Custom overload\n";
    return std::advance(f, x);

}

int main() {
    const std::vector<int> nums{1, 2, 3, 4, 5, 6, 7, 8, 9};

    auto even_only_custom = Filtered_Range([] (auto n) { return (n % 2 == 0); }, nums);
    auto x = even_only_custom.begin();
    std::cout << "First Value = " << *(x) << "\n";
    std::cout << "Second Value = " << *(x + 1);  //error here
}

GCC 11.2 错误信息

<source>: In function 'int main()':
<source>:47:43: error: no match for 'operator+' (operand types are 'boost::iterators::filter_iterator<boost::range_detail::default_constructible_unary_fn_wrapper<main()::<lambda(auto:2)>, bool>, __gnu_cxx::__normal_iterator<const int*, std::vector<int> > >' and 'int')
   47 |     std::cout << "Second Value = " << *(x + 1);
      |                                         ~ ^ ~
      |                                         |   |
      |                                         |   int
      |                                         boost::iterators::filter_iterator<boost::range_detail::default_constructible_unary_fn_wrapper<main()::<lambda(auto:2)>, bool>, __gnu_cxx::__normal_iterator<const int*, std::vector<int> > >
<source>:28:1: note: candidate: 'template<class TPredicate, class TRange> typename Filtered_Range<TPredicate, TRange>::filter_iterator& operator+(typename Filtered_Range<TPredicate, TRange>::filter_iterator&, int32_t)'
   28 | operator+(typename
      | ^~~~~~~~
<source>:28:1: note:   template argument deduction/substitution failed:
<source>:47:45: note:   couldn't deduce template parameter 'TPredicate'
   47 |     std::cout << "Second Value = " << *(x + 1);
      |                                             ^
In file included from /opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/bits/stl_algobase.h:67,
                 from /opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/bits/char_traits.h:39,
                 from /opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/ios:40,
                 from /opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/ostream:38,
                 from /opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/iostream:39,
                 from <source>:1:
/opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/bits/stl_iterator.h:568:5: note: candidate: 'template<class _Iterator> constexpr std::reverse_iterator<_Iterator> std::operator+(typename std::reverse_iterator<_Iterator>::difference_type, const std::reverse_iterator<_Iterator>&)'
  568 |     operator+(typename reverse_iterator<_Iterator>::difference_type __n,
      |     ^~~~~~~~
/opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/bits/stl_iterator.h:568:5: note:   template argument deduction/substitution failed:
<source>:47:45: note:   mismatched types 'const std::reverse_iterator<_Iterator>' and 'int'
   47 |     std::cout << "Second Value = " << *(x + 1);
      |                                             ^
In file included from /opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/bits/stl_algobase.h:67,
                 from /opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/bits/char_traits.h:39,
                 from /opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/ios:40,
                 from /opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/ostream:38,
                 from /opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/iostream:39,
                 from <source>:1:
/opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/bits/stl_iterator.h:1646:5: note: candidate: 'template<class _Iterator> constexpr std::move_iterator<_IteratorL> std::operator+(typename std::move_iterator<_IteratorL>::difference_type, const std::move_iterator<_IteratorL>&)'
 1646 |     operator+(typename move_iterator<_Iterator>::difference_type __n,
      |     ^~~~~~~~
/opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/bits/stl_iterator.h:1646:5: note:   template argument deduction/substitution failed:
<source>:47:45: note:   mismatched types 'const std::move_iterator<_IteratorL>' and 'int'
   47 |     std::cout << "Second Value = " << *(x + 1);
      |                                             ^
In file included from /opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/string:55,
                 from /opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/bits/locale_classes.h:40,
                 from /opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/bits/ios_base.h:41,
                 from /opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/ios:42,
                 from /opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/ostream:38,
                 from /opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/iostream:39,
                 from <source>:1:
/opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/bits/basic_string.h:6094:5: note: candidate: 'template<class _CharT, class _Traits, class _Alloc> std::__cxx11::basic_string<_CharT, _Traits, _Allocator> std::operator+(const std::__cxx11::basic_string<_CharT, _Traits, _Allocator>&, const std::__cxx11::basic_string<_CharT, _Traits, _Allocator>&)'
 6094 |     operator+(const basic_string<_CharT, _Traits, _Alloc>& __lhs,
      |     ^~~~~~~~
/opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/bits/basic_string.h:6094:5: note:   template argument deduction/substitution failed:
<source>:47:45: note:   'boost::iterators::filter_iterator<boost::range_detail::default_constructible_unary_fn_wrapper<main()::<lambda(auto:2)>, bool>, __gnu_cxx::__normal_iterator<const int*, std::vector<int> > >' is not derived from 'const std::__cxx11::basic_string<_CharT, _Traits, _Allocator>'
   47 |     std::cout << "Second Value = " << *(x + 1);
      |                                             ^
In file included from /opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/string:56,
                 from /opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/bits/locale_classes.h:40,
                 from /opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/bits/ios_base.h:41,
                 from /opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/ios:42,
                 from /opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/ostream:38,
                 from /opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/iostream:39,
                 from <source>:1:
/opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/bits/basic_string.tcc:1169:5: note: candidate: 'template<class _CharT, class _Traits, class _Alloc> std::__cxx11::basic_string<_CharT, _Traits, _Allocator> std::operator+(const _CharT*, const std::__cxx11::basic_string<_CharT, _Traits, _Allocator>&)'
 1169 |     operator+(const _CharT* __lhs,
      |     ^~~~~~~~
/opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/bits/basic_string.tcc:1169:5: note:   template argument deduction/substitution failed:
<source>:47:45: note:   mismatched types 'const _CharT*' and 'boost::iterators::filter_iterator<boost::range_detail::default_constructible_unary_fn_wrapper<main()::<lambda(auto:2)>, bool>, __gnu_cxx::__normal_iterator<const int*, std::vector<int> > >'
   47 |     std::cout << "Second Value = " << *(x + 1);
      |                                             ^
In file included from /opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/string:56,
                 from /opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/bits/locale_classes.h:40,
                 from /opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/bits/ios_base.h:41,
                 from /opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/ios:42,
                 from /opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/ostream:38,
                 from /opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/iostream:39,
                 from <source>:1:
/opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/bits/basic_string.tcc:1189:5: note: candidate: 'template<class _CharT, class _Traits, class _Alloc> std::__cxx11::basic_string<_CharT, _Traits, _Allocator> std::operator+(_CharT, const std::__cxx11::basic_string<_CharT, _Traits, _Allocator>&)'
 1189 |     operator+(_CharT __lhs, const basic_string<_CharT, _Traits, _Alloc>& __rhs)
      |     ^~~~~~~~
/opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/bits/basic_string.tcc:1189:5: note:   template argument deduction/substitution failed:
<source>:47:45: note:   mismatched types 'const std::__cxx11::basic_string<_CharT, _Traits, _Allocator>' and 'int'
   47 |     std::cout << "Second Value = " << *(x + 1);
      |                                             ^
In file included from /opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/string:55,
                 from /opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/bits/locale_classes.h:40,
                 from /opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/bits/ios_base.h:41,
                 from /opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/ios:42,
                 from /opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/ostream:38,
                 from /opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/iostream:39,
                 from <source>:1:
/opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/bits/basic_string.h:6131:5: note: candidate: 'template<class _CharT, class _Traits, class _Alloc> std::__cxx11::basic_string<_CharT, _Traits, _Allocator> std::operator+(const std::__cxx11::basic_string<_CharT, _Traits, _Allocator>&, const _CharT*)'
 6131 |     operator+(const basic_string<_CharT, _Traits, _Alloc>& __lhs,
      |     ^~~~~~~~
/opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/bits/basic_string.h:6131:5: note:   template argument deduction/substitution failed:
<source>:47:45: note:   'boost::iterators::filter_iterator<boost::range_detail::default_constructible_unary_fn_wrapper<main()::<lambda(auto:2)>, bool>, __gnu_cxx::__normal_iterator<const int*, std::vector<int> > >' is not derived from 'const std::__cxx11::basic_string<_CharT, _Traits, _Allocator>'
   47 |     std::cout << "Second Value = " << *(x + 1);
      |                                             ^
In file included from /opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/string:55,
                 from /opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/bits/locale_classes.h:40,
                 from /opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/bits/ios_base.h:41,
                 from /opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/ios:42,
                 from /opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/ostream:38,
                 from /opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/iostream:39,
                 from <source>:1:
/opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/bits/basic_string.h:6147:5: note: candidate: 'template<class _CharT, class _Traits, class _Alloc> std::__cxx11::basic_string<_CharT, _Traits, _Allocator> std::operator+(const std::__cxx11::basic_string<_CharT, _Traits, _Allocator>&, _CharT)'
 6147 |     operator+(const basic_string<_CharT, _Traits, _Alloc>& __lhs, _CharT __rhs)
      |     ^~~~~~~~
/opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/bits/basic_string.h:6147:5: note:   template argument deduction/substitution failed:
<source>:47:45: note:   'boost::iterators::filter_iterator<boost::range_detail::default_constructible_unary_fn_wrapper<main()::<lambda(auto:2)>, bool>, __gnu_cxx::__normal_iterator<const int*, std::vector<int> > >' is not derived from 'const std::__cxx11::basic_string<_CharT, _Traits, _Allocator>'
   47 |     std::cout << "Second Value = " << *(x + 1);
      |                                             ^
In file included from /opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/string:55,
                 from /opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/bits/locale_classes.h:40,
                 from /opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/bits/ios_base.h:41,
                 from /opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/ios:42,
                 from /opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/ostream:38,
                 from /opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/iostream:39,
                 from <source>:1:
/opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/bits/basic_string.h:6159:5: note: candidate: 'template<class _CharT, class _Traits, class _Alloc> std::__cxx11::basic_string<_CharT, _Traits, _Allocator> std::operator+(std::__cxx11::basic_string<_CharT, _Traits, _Allocator>&&, const std::__cxx11::basic_string<_CharT, _Traits, _Allocator>&)'
 6159 |     operator+(basic_string<_CharT, _Traits, _Alloc>&& __lhs,
      |     ^~~~~~~~
/opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/bits/basic_string.h:6159:5: note:   template argument deduction/substitution failed:
<source>:47:45: note:   'boost::iterators::filter_iterator<boost::range_detail::default_constructible_unary_fn_wrapper<main()::<lambda(auto:2)>, bool>, __gnu_cxx::__normal_iterator<const int*, std::vector<int> > >' is not derived from 'std::__cxx11::basic_string<_CharT, _Traits, _Allocator>'
   47 |     std::cout << "Second Value = " << *(x + 1);
      |                                             ^
In file included from /opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/string:55,
                 from /opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/bits/locale_classes.h:40,
                 from /opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/bits/ios_base.h:41,
                 from /opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/ios:42,
                 from /opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/ostream:38,
                 from /opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/iostream:39,
                 from <source>:1:
/opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/bits/basic_string.h:6165:5: note: candidate: 'template<class _CharT, class _Traits, class _Alloc> std::__cxx11::basic_string<_CharT, _Traits, _Allocator> std::operator+(const std::__cxx11::basic_string<_CharT, _Traits, _Allocator>&, std::__cxx11::basic_string<_CharT, _Traits, _Allocator>&&)'
 6165 |     operator+(const basic_string<_CharT, _Traits, _Alloc>& __lhs,
      |     ^~~~~~~~
/opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/bits/basic_string.h:6165:5: note:   template argument deduction/substitution failed:
<source>:47:45: note:   'boost::iterators::filter_iterator<boost::range_detail::default_constructible_unary_fn_wrapper<main()::<lambda(auto:2)>, bool>, __gnu_cxx::__normal_iterator<const int*, std::vector<int> > >' is not derived from 'const std::__cxx11::basic_string<_CharT, _Traits, _Allocator>'
   47 |     std::cout << "Second Value = " << *(x + 1);
      |                                             ^
In file included from /opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/string:55,
                 from /opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/bits/locale_classes.h:40,
                 from /opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/bits/ios_base.h:41,
                 from /opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/ios:42,
                 from /opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/ostream:38,
                 from /opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/iostream:39,
                 from <source>:1:
/opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/bits/basic_string.h:6171:5: note: candidate: 'template<class _CharT, class _Traits, class _Alloc> std::__cxx11::basic_string<_CharT, _Traits, _Allocator> std::operator+(std::__cxx11::basic_string<_CharT, _Traits, _Allocator>&&, std::__cxx11::basic_string<_CharT, _Traits, _Allocator>&&)'
 6171 |     operator+(basic_string<_CharT, _Traits, _Alloc>&& __lhs,
      |     ^~~~~~~~
/opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/bits/basic_string.h:6171:5: note:   template argument deduction/substitution failed:
<source>:47:45: note:   'boost::iterators::filter_iterator<boost::range_detail::default_constructible_unary_fn_wrapper<main()::<lambda(auto:2)>, bool>, __gnu_cxx::__normal_iterator<const int*, std::vector<int> > >' is not derived from 'std::__cxx11::basic_string<_CharT, _Traits, _Allocator>'
   47 |     std::cout << "Second Value = " << *(x + 1);
      |                                             ^
In file included from /opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/string:55,
                 from /opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/bits/locale_classes.h:40,
                 from /opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/bits/ios_base.h:41,
                 from /opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/ios:42,
                 from /opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/ostream:38,
                 from /opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/iostream:39,
                 from <source>:1:
/opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/bits/basic_string.h:6193:5: note: candidate: 'template<class _CharT, class _Traits, class _Alloc> std::__cxx11::basic_string<_CharT, _Traits, _Allocator> std::operator+(const _CharT*, std::__cxx11::basic_string<_CharT, _Traits, _Allocator>&&)'
 6193 |     operator+(const _CharT* __lhs,
      |     ^~~~~~~~
/opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/bits/basic_string.h:6193:5: note:   template argument deduction/substitution failed:
<source>:47:45: note:   mismatched types 'const _CharT*' and 'boost::iterators::filter_iterator<boost::range_detail::default_constructible_unary_fn_wrapper<main()::<lambda(auto:2)>, bool>, __gnu_cxx::__normal_iterator<const int*, std::vector<int> > >'
   47 |     std::cout << "Second Value = " << *(x + 1);
      |                                             ^
In file included from /opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/string:55,
                 from /opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/bits/locale_classes.h:40,
                 from /opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/bits/ios_base.h:41,
                 from /opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/ios:42,
                 from /opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/ostream:38,
                 from /opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/iostream:39,
                 from <source>:1:
/opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/bits/basic_string.h:6199:5: note: candidate: 'template<class _CharT, class _Traits, class _Alloc> std::__cxx11::basic_string<_CharT, _Traits, _Allocator> std::operator+(_CharT, std::__cxx11::basic_string<_CharT, _Traits, _Allocator>&&)'
 6199 |     operator+(_CharT __lhs,
      |     ^~~~~~~~
/opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/bits/basic_string.h:6199:5: note:   template argument deduction/substitution failed:
<source>:47:45: note:   mismatched types 'std::__cxx11::basic_string<_CharT, _Traits, _Allocator>' and 'int'
   47 |     std::cout << "Second Value = " << *(x + 1);
      |                                             ^
In file included from /opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/string:55,
                 from /opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/bits/locale_classes.h:40,
                 from /opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/bits/ios_base.h:41,
                 from /opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/ios:42,
                 from /opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/ostream:38,
                 from /opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/iostream:39,
                 from <source>:1:
/opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/bits/basic_string.h:6205:5: note: candidate: 'template<class _CharT, class _Traits, class _Alloc> std::__cxx11::basic_string<_CharT, _Traits, _Allocator> std::operator+(std::__cxx11::basic_string<_CharT, _Traits, _Allocator>&&, const _CharT*)'
 6205 |     operator+(basic_string<_CharT, _Traits, _Alloc>&& __lhs,
      |     ^~~~~~~~
/opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/bits/basic_string.h:6205:5: note:   template argument deduction/substitution failed:
<source>:47:45: note:   'boost::iterators::filter_iterator<boost::range_detail::default_constructible_unary_fn_wrapper<main()::<lambda(auto:2)>, bool>, __gnu_cxx::__normal_iterator<const int*, std::vector<int> > >' is not derived from 'std::__cxx11::basic_string<_CharT, _Traits, _Allocator>'
   47 |     std::cout << "Second Value = " << *(x + 1);
      |                                             ^
In file included from /opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/string:55,
                 from /opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/bits/locale_classes.h:40,
                 from /opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/bits/ios_base.h:41,
                 from /opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/ios:42,
                 from /opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/ostream:38,
                 from /opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/iostream:39,
                 from <source>:1:
/opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/bits/basic_string.h:6211:5: note: candidate: 'template<class _CharT, class _Traits, class _Alloc> std::__cxx11::basic_string<_CharT, _Traits, _Allocator> std::operator+(std::__cxx11::basic_string<_CharT, _Traits, _Allocator>&&, _CharT)'
 6211 |     operator+(basic_string<_CharT, _Traits, _Alloc>&& __lhs,
      |     ^~~~~~~~
/opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/bits/basic_string.h:6211:5: note:   template argument deduction/substitution failed:
<source>:47:45: note:   'boost::iterators::filter_iterator<boost::range_detail::default_constructible_unary_fn_wrapper<main()::<lambda(auto:2)>, bool>, __gnu_cxx::__normal_iterator<const int*, std::vector<int> > >' is not derived from 'std::__cxx11::basic_string<_CharT, _Traits, _Allocator>'
   47 |     std::cout << "Second Value = " << *(x + 1);
      |                                             ^
In file included from /opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/bits/stl_algobase.h:67,
                 from /opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/bits/char_traits.h:39,
                 from /opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/ios:40,
                 from /opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/ostream:38,
                 from /opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/iostream:39,
                 from <source>:1:
/opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/bits/stl_iterator.h:1242:5: note: candidate: 'template<class _Iterator, class _Container> __gnu_cxx::__normal_iterator<_Iterator, _Container> __gnu_cxx::operator+(typename __gnu_cxx::__normal_iterator<_Iterator, _Container>::difference_type, const __gnu_cxx::__normal_iterator<_Iterator, _Container>&)'
 1242 |     operator+(typename __normal_iterator<_Iterator, _Container>::difference_type
      |     ^~~~~~~~
/opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/bits/stl_iterator.h:1242:5: note:   template argument deduction/substitution failed:
<source>:47:45: note:   mismatched types 'const __gnu_cxx::__normal_iterator<_Iterator, _Container>' and 'int'
   47 |     std::cout << "Second Value = " << *(x + 1);
      |                                             ^
In file included from /opt/compiler-explorer/libs/boost_1_67_0/boost/range/iterator_range_core.hpp:27,
                 from /opt/compiler-explorer/libs/boost_1_67_0/boost/range/iterator_range.hpp:13,
                 from /opt/compiler-explorer/libs/boost_1_67_0/boost/range/adaptor/filtered.hpp:16,
                 from <source>:3:
/opt/compiler-explorer/libs/boost_1_67_0/boost/iterator/iterator_facade.hpp:955:3: note: candidate: 'template<class Derived, class V, class TC, class R, class D> typename boost::iterators::enable_if<boost::iterators::detail::is_traversal_at_least<TC, boost::iterators::random_access_traversal_tag>, Derived>::type boost::iterators::operator+(const boost::iterators::iterator_facade<Derived1, V1, TC1, Reference1, Difference1>&, typename Derived::difference_type)'
  955 |   BOOST_ITERATOR_FACADE_PLUS((
      |   ^~~~~~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/libs/boost_1_67_0/boost/iterator/iterator_facade.hpp:955:3: note:   template argument deduction/substitution failed:
/opt/compiler-explorer/libs/boost_1_67_0/boost/iterator/iterator_facade.hpp: In substitution of 'template<class Derived, class V, class TC, class R, class D> typename boost::iterators::enable_if<boost::iterators::detail::is_traversal_at_least<TC, boost::iterators::random_access_traversal_tag>, Derived>::type boost::iterators::operator+(const boost::iterators::iterator_facade<Derived1, V1, TC1, Reference1, Difference1>&, typename Derived::difference_type) [with Derived = boost::iterators::filter_iterator<boost::range_detail::default_constructible_unary_fn_wrapper<main()::<lambda(auto:2)>, bool>, __gnu_cxx::__normal_iterator<const int*, std::vector<int> > >; V = int; TC = boost::iterators::bidirectional_traversal_tag; R = const int&; D = long int]':
<source>:47:45:   required from here
/opt/compiler-explorer/libs/boost_1_67_0/boost/iterator/iterator_facade.hpp:955:3: error: no type named 'type' in 'struct boost::iterators::enable_if<boost::iterators::detail::is_traversal_at_least<boost::iterators::bidirectional_traversal_tag, boost::iterators::random_access_traversal_tag>, boost::iterators::filter_iterator<boost::range_detail::default_constructible_unary_fn_wrapper<main()::<lambda(auto:2)>, bool>, __gnu_cxx::__normal_iterator<const int*, std::vector<int> > > >'
/opt/compiler-explorer/libs/boost_1_67_0/boost/iterator/iterator_facade.hpp:960:3: note: candidate: 'template<class Derived, class V, class TC, class R, class D> typename boost::iterators::enable_if<boost::iterators::detail::is_traversal_at_least<TC, boost::iterators::random_access_traversal_tag>, Derived>::type boost::iterators::operator+(typename Derived::difference_type, const boost::iterators::iterator_facade<Derived1, V1, TC1, Reference1, Difference1>&)'
  960 |   BOOST_ITERATOR_FACADE_PLUS((
      |   ^~~~~~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/libs/boost_1_67_0/boost/iterator/iterator_facade.hpp:960:3: note:   template argument deduction/substitution failed:
<source>:47:45: note:   mismatched types 'const boost::iterators::iterator_facade<Derived1, V1, TC1, Reference1, Difference1>' and 'int'
   47 |     std::cout << "Second Value = " << *(x + 1);
      |                                             ^
Execution build compiler returned: 1


任何关于错误的指示和可能的解决方案将不胜感激。 谢谢!

template <typename T>
    void foo(typename T::nested_type) {}

T 在 non-deduced context¹ 中。这意味着唯一可以让它工作的方法是使用 SFINAE。

namespace detail {
    template <typename T> struct is_filt_it : std::false_type { };

    template <typename... Args>
    struct is_filt_it<boost::filter_iterator<Args...>> : std::true_type { };
} // namespace detail

template <typename It>
static decltype(auto) operator+(It it, std::enable_if_t<detail::is_filt_it<It>::value, int32_t> x)
{
    return std::next(it, x);
}

现在重载始终参与,但因 non-filter_iterator 个参数被 SFINAE 丢弃:

Live On Coliru

#undef NDEBUG
#include <boost/range/adaptor/filtered.hpp>
#include <iostream>
#include <vector>

template <typename TPredicate, typename TRange>
struct Filtered_Range : boost::filtered_range<TPredicate, TRange> {
    using base_type = boost::filtered_range<TPredicate, TRange>;
    using base_type::base_type;

    auto operator[](size_t i) const {
        assert(i < this->size());
        return *std::next(base_type::begin(), i);
    }
};

template <typename TPredicate, typename TRange>
Filtered_Range(TPredicate const&, TRange const&) -> Filtered_Range<TPredicate, TRange>;

namespace detail {
    template <typename T> struct is_filt_it : std::false_type { };

    template <typename... Args>
    struct is_filt_it<boost::filter_iterator<Args...>> : std::true_type { };
} // namespace detail

template <typename It>
static decltype(auto) operator+(It it, std::enable_if_t<detail::is_filt_it<It>::value, int32_t> x)
{
    return std::next(it, x);
}

int main() {
    std::vector nums{1, 2, 3, 4, 5, 6, 7, 8, 9};

    auto evens = Filtered_Range([](auto n) { return (n % 2 == 0); }, nums);
    auto it    = evens.begin();
    std::cout << "First  Value = " << *(it) << "\n";
    std::cout << "Second Value = " << *(it + 1) << "\n";
}

版画

First  Value = 2
Second Value = 4

¹ 另见例如What is a nondeduced context?


控制实例化

要限制 operator+ 仅支持自定义范围子类,您必须使迭代器类型可区分。

“累人”的方法是 subclass/wrap 迭代器并委托所有范围接口来使用它们。

“有线”方式将包装 Predicate(它显示为 filter_iterator 类型的第一个模板参数!)。这样我们就可以查看 filter_iterator 的参数“内部”,以检测谓词何时被适当地“标记”。

尝试 #1(天真)

namespace MyLib {
    template <typename F> struct Tagged : F {
        Tagged(F f) : F(std::move(f)) {}
        using F::operator();
    };
} // namespace MyLib

现在,我们在自定义子类中装饰 TPredicate:

template <typename TPredicate, typename TRange>
struct Filtered_Range : boost::filtered_range<MyLib::Tagged<TPredicate>, TRange> {
    using base_type = boost::filtered_range<MyLib::Tagged<TPredicate>, TRange>;
    using base_type::base_type;

    auto operator[](size_t i) const {
        assert(i < this->size());
        return *std::next(base_type::begin(), i);
    }

    using const_iterator = typename boost::range_iterator<base_type, void>::type;
};

并且我们扩展 is_filt_it 特性来检查 Tagged<> 谓词:

namespace detail {
    template <typename T> struct is_tagged : std::false_type { };
    template <typename F> struct is_tagged<MyLib::Tagged<F>> : std::true_type { };

    template <typename T, typename = void> struct is_filt_it : std::false_type { };

    template <typename F, typename... Args>
    struct is_filt_it<boost::filter_iterator<F, Args...>,
                      std::enable_if_t<is_tagged<F>::value>> : std::true_type {
    };
} // namespace detail

遗憾的是,这中断了:

Candidate template ignored: requirement 'detail::is_filt_it<boost::iterators::filter_iterator<boost::range_detail::default_constructible_unary_fn_wrapper<MyLib::Tagged<...>, bool>...

如您所见,Boost 已经 包装器(至少有时)并且它打破了我们的检测

尝试 #2(银河大脑)

那么我们是否会变得乏味并更改实际的迭代器类型?

没有! C++ 中有一个有时有点毒的特性:参数相关查找。 ADL 旨在引入“关联的命名空间”以供查找。事实证明,声明在模板参数(及其模板参数)中命名的类型的命名空间被认为是“关联的”。

所以:

namespace MyLib {
    namespace AdlBarrier {
        template <typename F> struct Tagged : F {
            Tagged(F f) : F(std::move(f)) {}
            using F::operator();
        };

        template <typename T> constexpr bool is_tagged(T&&) { return true; }
    } // namespace AdlBarrier

    using AdlBarrier::Tagged;
} // namespace MyLib

Filtered_Range 没有变化,并且:

namespace detail {
    template <typename T, typename = void> struct is_filt_it : std::false_type { };

    template <typename F, typename... Args>
    struct is_filt_it<boost::filter_iterator<F, Args...>,
                      std::enable_if_t<is_tagged(static_cast<F*>(nullptr))>>
        : std::true_type {
    };
} // namespace detail

现在,您可以对自定义范围内的迭代器进行特殊处理:

{
    auto evens = Filtered_Range([](auto n) { return (n % 2 == 0); }, nums);
    auto it    = evens.begin();
    std::cout << "First  Value = " << *(it) << "\n";
    std::cout << "Second Value = " << *(it + 1) << "\n";
}

但是普通香草 boost::filtered_range 没有得到特殊待遇:

{
    auto odds = boost::filtered_range([](auto n) { return (n % 2 == 1); }, nums);
    auto it   = odds.begin();
    std::cout << "First  Value = " << *(it) << "\n";
    std::cout << "Second Value = " << *(it + 1) << "\n"; // doesn't compile
}

现场观看:https://godbolt.org/z/xhqjqa3Gc (or correctly not-compiling: https://godbolt.org/z/67vP6TEGc)