Take a look at this code:
#include <vector> #include <functional> template<typename RandIt, typename T, typename Pred> auto search_with(RandIt begin, RandIt end, const T& value, Pred&& pred) noexcept { //... return begin; } template<typename RandIt, typename T> auto search_with(RandIt begin, RandIt end, const T& value) noexcept { return search_with(begin, end, value, std::less<T>{}); } template<typename Array, typename T, typename Pred> auto search_with(const Array& array, const T& value, Pred&& pred) noexcept { return search_with(std::begin(array), std::end(array), value, std::forward<Pred>(pred)); } int main() { std::vector<int> v = { 1, 2, 3 }; search_with(v, 10, std::less<int>{}); // ok search_with(v.begin(), v.end(), 10); // fail! }
I donโt understand why in the second call to search_with
compiler chooses the third overload. If I comment on the third overload, then the code compiles fine. This indicates that the second overload is not discarded as it is compiled and should be a valid overload.
However, a third overload was selected, which does not execute, since there is no specialization for iterators std::begin
(and std::end
):
main.cpp: In instantiation of 'auto search_with(const Array&, const T&, Pred&&) [with Array = __gnu_cxx::__normal_iterator<int*, std::vector<int> >; T = __gnu_cxx::__normal_iterator<int*, std::vector<int> >; Pred = int]': main.cpp:23:39: required from here main.cpp:17:34: error: no matching function for call to 'begin(const __gnu_cxx::__normal_iterator<int*, std::vector<int> >&)' return search_with(std::begin(array), std::end(array), value, std::forward<Pred>(pred)); ~~~~~~~~~~^~~~~~~
I would think that the opposite is happening: the third overload is discarded because it does not compile, and the second is selected.
But this is obviously not the case, so what happens here? Why is the wrong overload selected? Why is the third overload better than the second?