Lambdas and std::function

前端 未结 2 728
伪装坚强ぢ
伪装坚强ぢ 2020-12-04 02:21

I\'m trying to catch up on C++11 and all the great new features. I\'m a bit stuck on lambdas.

Here\'s the code I was able to get to work:

#include &         


        
相关标签:
2条回答
  • 2020-12-04 02:46

    Stephan T. Lavavej explains why this doesn't work in this video. Basically, the problem is that the compiler tries to deduce BaseT from both the std::vector and the std::function parameter. A lambda in C++ is not of type std::function, it's an unnamed, unique non-union type that is convertible to a function pointer if it doesn't have a capture list (empty []). On the other hand, a std::function object can be created from any possible type of callable entity (function pointers, member function pointers, function objects).

    Note that I personally don't understand why you would want to limit the incoming functors to that specific signature (in addition to the fact that indirection through a polymorphic function wrapper, like std::function, is by far more inefficient than a direct call to a functor (which may even be inlined)), but here's a working version. Basically, it disables argument deduction on the std::function part, and only deduces BaseT from the std::vector argument:

    template<class T>
    struct Identity{
      typedef T type;
    };
    
    template<typename BaseT>
    vector<BaseT> findMatches(vector<BaseT> search, 
        typename Identity<function<bool (const BaseT &)>>::type func)
    {
        vector<BaseT> tmp;
    
        for(auto item : search)
        {
            if( func(item) )
            {
                tmp.push_back(item);
            }
        }
    
        return tmp;
    }
    

    Live example on Ideone.

    Another possible way would be to not restrict the functor type directly, but indirectly through SFINAE:

    template<class T, class F>
    auto f(std::vector<T> v, F fun)
        -> decltype(bool(fun(v[0])), void())
    {
      // ...
    }
    

    Live example on Ideone.

    This function will be removed from the overload set if fun doesn't take an argument of type T& or if the return type is not convertible to bool. The , void() makes f's return type void.

    0 讨论(0)
  • 2020-12-04 02:53

    As has been revealed by other posters, this is a template argument deduction for std::function.

    One intuitive way to make the second code snippet work is to add your base type when calling the template function: findMatches<int>.

    Another way not mentioned by Xeo is using std::is_convertible:

    template<typename BaseT, typename FUNC>
    vector<BaseT> findMatches(vector<BaseT> search, function <bool (const BaseT &)> func)
    {
        static_assert(std::is_convertible<FUNC, function<bool (const BaseT &)> >::value, "func must be convertible to ...");
    
        vector<BaseT> tmp;
    
        for(auto item : search)
        {
            if( func(item) )
            {
                tmp.push_back(item);
            }
        }
    
        return tmp;
    }
    

    It avoids wrapping lamda into std::function, and provides a cleaner error message.

    0 讨论(0)
提交回复
热议问题