1

I have a function like this :

template<typename Iterator>
void sort2(Iterator it,
           std::function<bool(typename std::remove_pointer<
                              typename  Iterator::iterator_type>::type,
                                          int)> func)
{
}

int main()
{
    std::vector<int> a;
    sort2(a.begin(),[](int,int){return false;});
}
'main()::__lambda0' is not derived from 'std::function<bool(typename std::remove_pointer<typename Iterator::iterator_type>::type, int)>'
 sort2(a.begin(),[](int,int){return false;});
                                           ^

When I change it to :

template<typename Iterator>
void sort2(Iterator it,
           std::function<bool(typename std::remove_pointer<
                              typename  vector<int>::iterator/*I change this*/::iterator_type>::type,
                                          int)> func)
{
}

It compiles fine ...

What is wrong with the first function ?!

It seems correct ... why does it give compile errors ?

8
  • 1
    iterator::iterator_type will be a tag type (in this case, std::random_access). You probably just want Iterator::reference Commented May 27, 2014 at 13:47
  • 1
    Though I would point out that I would just template the second argument so that function pointers and operator structs could be used as well. Commented May 27, 2014 at 13:48
  • Note: passing a single iterator instead of a range will not work (although, it is an example) Commented May 27, 2014 at 13:53
  • Your code compiles on gcc-4.9 and clang-3.4 Commented May 27, 2014 at 13:57
  • 2
    @MadScienceDreams Iterator::iterator_type won't be anything - you're thinking of std::iterator_traits<Iterator>::iterator_category. Commented May 27, 2014 at 14:16

1 Answer 1

3

Iterators have no member named iterator_type. You want Iterator::value_type (Live at Coliru):

template<typename Iterator>
void sort2(Iterator it,
           std::function<bool(typename std::remove_pointer<
                              typename Iterator::value_type>::type,
                                          int)> func)
{
}

or better yet, use std::iterator_traits<Iterator>::value_type so your function will accept pointers as well as class type iterators (Coliru again):

template<typename Iterator>
void sort2(Iterator it,
           std::function<bool(typename std::remove_pointer<
                              typename std::iterator_traits<Iterator>::value_type>::type,
                                          int)> func)
{
}

A more generic version would accept the comparator type as a template parameter and use SFINAE to constrain that type to functions callable with two value_types having a return type convertible to bool instead of using convertibility to std::function<bool(value_type, value_type):

template <typename Iterator>
using ValueType = typename std::iterator_traits<Iterator>::value_type;

template<typename Iterator, typename Function>
auto sort2(Iterator first, Iterator last, Function func) ->
  typename std::enable_if<
    std::is_convertible<decltype(func(std::declval<ValueType<Iterator>>(),
                                      std::declval<ValueType<Iterator>>())),
                        bool>::value
  >::type
{
    std::sort(first, last, func);
}

It's hideously ugly - constraining with SFINAE always is - but at least gcc compiles it successfully.

Sign up to request clarification or add additional context in comments.

2 Comments

gcc still doesn't compile it. And iterator_type looked strange to me too, but I found some MSDN doc that talked about it.
@omid gcc compiles it if you force the second argument to be in a non-deduced context. So I suppose the question here is which compiler is wrong.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.