如何接受泛型迭代器?

时间:2013-09-07 10:08:19

标签: c++ c++11 polymorphism

我希望构造函数接受任何具有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());

我可以在这做什么?

2 个答案:

答案 0 :(得分:3)

怎么样:

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*

答案 1 :(得分:1)

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

例如,

    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 *上的随机访问迭代器,请使用static_assert个条件为std::is_same的{​​{1}}个sbabbi的答案。由此产生的用户体验优于纯SFINAE,因为错误消息显示“请传递随机访问迭代器”,而不是“未发现过载。”