如何接受泛型迭代器

How to accept generic iterators?

本文关键字:迭代器 泛型 何接受      更新时间:2023-10-16

我希望构造函数接受任何具有x特征并引用类y的迭代器。

Class(std::iterator<std::random_access_iterator_tag, MyClass*> it);

但是当我尝试传递这样的迭代器时,编译失败并出现Candidate constructor not viable: no known conversion from 'iterator' (aka '__deque_iterator<value_type, pointer, reference, __map_pointer, difference_type, __block_size>') to 'std::iterator<std::random_access_iterator_tag, MyClass *>'.

插入代码:

std::deque<MyClass*> collection_with_random_access_iterator{};
Class tmp(collection_with_random_access_iterator.begin());

我能在这里做什么?

怎么样:

template<class Iterator>
Class(Iterator it,
  typename std::enable_if<
          std::is_same<
                  typename std::iterator_traits<Iterator>::value_type,
                  MyClass*
          >::value //checks for value_type
          &&
          std::is_base_of<
                  std::random_access_iterator_tag,
                  typename std::iterator_traits<Iterator>::iterator_category
          >::value //checks for iterator category
    >::type * = 0);

编辑 此外,您还应考虑将第一个std::is_same替换为 std::is_convertible ,如果您不打算修改输入,请检查const MyClass*

迭代器通常由值接受,然后通过委托给其他函数来区分。

例如

    template< typename iterator >
    Class( iterator it ) {
        init_class( * it, typename std::iterator_traits< iterator >::category() );
    }
    template< typename iterator >
    void init_class( iterator it, std::random_access_iterator_tag ) {
        for ( int i = 0; i != 42; i +=3 ) {
            do_something( it[ i ] );
        }
    }
    void do_something( MyClass * ) { … }
};

传递错误的迭代器会导致函数内部出现错误,这对用户来说可能是神秘的。但这就是标准库实现中通常发生的事情,也是在 SFINAE 发明之前最初使用迭代器的方式。如果存在常见的用户错误,您可以专门捕获它们并引导用户访问特定的错误/注释。

如果不需要选择不同的行为,但希望确保用户通过MyClass *传递随机访问迭代器,请使用带有std::is_same条件的几个static_assert作为 sbbabi 的答案。生成的用户体验比纯 SFINAE 更好,因为错误消息显示"请传递随机访问迭代器",而不是"未找到重载"。