0

Compiling with g++ 7.4.0, with --std=c++11 option, the following code works perfectly:

template<typename T, typename funcT>
size_t find_index( // wrapper over std::find_if to return the element index
    const std::vector<T>& v,
    funcT&& func // function type is a template
) {
    typename std::vector<T>::const_iterator it =
        std::find_if(v.cbegin(), v.cend(), std::move(func));
    return it == v.cend() ? -1 : it - v.cbegin();
}

int main() { // usage example
    std::vector<int> nums = {10, 20, 30};
    size_t x = find_index(nums,
        [](const int& i) -> bool { return i == 10; });
    return 0;
}

However, if I change the function signature to this:

// This is how I'd like to write the function!
template<typename T>
size_t find_index(
    const std::vector<T>& v,
    std::function<bool(const T&)>&& func // function type is explicit now!
) {
    typename std::vector<T>::const_iterator it =
        std::find_if(v.cbegin(), v.cend(), std::move(func));
    return it == v.cend() ? -1 : it - v.cbegin();
}

Template deduction fails, and I receive the error:

a.cpp: In function ‘int main()’:
a.cpp:30:57: error: no matching function for call to ‘find_index(std::vector<int>&, main()::<lambda(const int&)>)’
                [](const int& i) -> bool { return i == 10; });
                                                                            ^
a.cpp:8:12: note: candidate: template<class T> size_t find_index(const std::vector<T>&, std::function<bool(const T&)>&&)
    size_t find_index(
                ^~~~~~~~~~
a.cpp:8:12: note:   template argument deduction/substitution failed:
a.cpp:30:57: note:   ‘main()::<lambda(const int&)>’ is not derived from ‘std::function<bool(const T&)>’
                [](const int& i) -> bool { return i == 10; });

In the other hand, if I explicit the function call template parameter, it works:

// I don't want to have to write it this way...
size_t x = find_index<int>(nums, // note explicit <int> template parameter
    [](const int& i) -> bool { return i == 10; });

Why can't the compiler deduce the int template parameter? What am I missing?

rodrigocfd
  • 6,450
  • 6
  • 34
  • 68
  • Tl;DR of the dupe: Templates never do conversions. A lambda is not a `std::function` so it can't deduce the `std::function` parameters. – NathanOliver Aug 27 '19 at 20:46
  • 1
    Also note the the only real use case for `std::function` is when you need to store arbitrary callables. If you are passing to a function just make the function object a template parameter like you do in your first block. That way you don't have to pay for type erasure and "it just works". – NathanOliver Aug 27 '19 at 20:48
  • 2
    `size_t x = find_index(nums, {[](const int& i) -> bool { return i == 10; }});` does the trick. – JulianW Aug 27 '19 at 20:58
  • @JulianH To my surprise, it indeed worked... care to elaborate what sorcery is this? – rodrigocfd Aug 28 '19 at 14:46
  • Don't know. Yesterday I looked for a few minitues, but couldn't find the paragraph. May be someone else can. But I think, with this way you pass the lambda more explicitly to the `std::function`'s constructor. – JulianW Aug 29 '19 at 07:53
  • I also don't get the "a lambda isn't a std::function" argument, since static conversation should take place here like we can see in my example. – JulianW Aug 29 '19 at 08:00
  • I asked a question here: https://stackoverflow.com/questions/57705788/call-a-function-with-stdfunction-as-argument-with-a-lambda – JulianW Aug 29 '19 at 08:07

0 Answers0