0x1337 0x1337 - 1 month ago 8
C++ Question

How properly pass comparator to another template function

I need a function that will take two iterators and a custom comparator to compare values of this iterators. I don't want use additional template argument for this. I've implemented it in this way:

template<typename T>
void foo(T begin, T end,
function<bool(decltype(*begin), decltype(*begin))> compare = less<decltype(*begin)>())
{
// I want to use 'compare' as: "compare(*begin, *begin);"
}


This code has been compiled normally by clang, but on GCC 5.4.0 I've got some errors:

binary_heap.cpp:10:79: error: local variable 'begin' may not appear in this context
function<bool(decltype(*begin), decltype(*begin))> compare = less<decltype(*begin)>())
^
binary_heap.cpp:10:85: error: template argument 1 is invalid
function<bool(decltype(*begin), decltype(*begin))> compare = less<decltype(*begin)>())


How to correct this code so that it can be successfully compiled on both clang and GCC? Or maybe are there a more suitable solution for defining such function?

Answer

You're pessimizing performance of your algorithm by a lot just by forcing the use of function (more details here). Just take template deduced Compare and you're golden:

template<typename T, typename Compare = std::less<typename iterator_traits<T>::value_type>>
void foo(T begin, T end, Compare compare = Compare{})
{
    // I want to use 'compare' as: "compare(*begin, *begin);"
}

Interestingly, standard algorithms force/suggest use of lightweight functors by taking them by value instead of a forwarding reference.


To answer the actual question: you can use std::less<>, which defaults to std::less<void> and has templated operator() doing the actual comparisons:

template<typename T>
void foo(T begin, T end,
  function<bool(decltype(*begin), decltype(*begin))> compare = less<>())
{
    // I want to use 'compare' as: "compare(*begin, *begin);"
}
Comments