Unfortunately, doing this completely right is a problem. However, you can do something reasonable (and will work in this case). Basically, you need to conditionally enable the second overload depending on whether the output type InputIt meets the requirements for inputting an iterator. There is a whole list of requirements for the input iterator: http://en.cppreference.com/w/cpp/concept/InputIterator . However, we will simply focus on resolving this situation and the most common cases for us. Namely, we will check whether the InputIt type InputIt correct operator* . We use the void_t trick to create a trait for this:
template <class ... T> using void_t = void; template <class T, class = void> struct has_iterator_deref : std::false_type {}; template <class T> struct has_iterator_deref<T, std::enable_if_t< std::is_same<typename std::iterator_traits<T>::reference, decltype(*std::declval<T>())>::value>> : std::true_type {};
Long and short is that this structure ensures that an instance of T can be dereferenced with * and will be of the same type as iterator_traits<T>::reference . Having done this, we now use this to hide the second overload:
template <typename T, typename Allocator> template <typename InputIt, class = enable_if_t<has_iterator_deref<T>::value>> typename Vector<T, Allocator>::iterator Vector<T, Allocator>::insert(const_iterator pos, InputIt first, InputIt last) ...
If you feel excited, you can actually go through the entire list of requirements for the input iterator, and as far as I can see, create a tag that determines if each one is present, and then finally take the connection with the correct detection to ensure Compliance of InputIt with the concept of Input Iterator. It is rather a pain, but.
Nir friedman
source share