Home > OS >  error C2672 and C2784 when using lamdas with template functions
error C2672 and C2784 when using lamdas with template functions

Time:03-31

I have written the following function which hides the loops when iterating over a 2d vector:

    template<typename ElementType>
    void iterateOver2DVector(std::vector<std::vector<ElementType>> & vec, 
                             std::function<void(ElementType & element)> function)
    {
        for(auto & row : vec)
        {
            for(auto & element : row)
            {
                function(element);
            }
        }
    }

but I get error:

'function': no matching overloaded function found

and

'declaration' : could not deduce template argument for 'type' from 'type'

when using it with lambdas like this:

iterateOver2DVector(graph, [](Node & node) { node.update(); } );

Does someone know what I do wrong?

CodePudding user response:

The call will try to deduce ElementType from both the first and second parameter/argument pair.

It will fail for the second pair, since the second argument to the function is not a std::function, but a closure type.

If it fails for one pair, then the whole deduction fails, even if the other pair would deduce the template argument for ElementType correctly.

Your function doesn't need to deduce ElementType from the second parameter/argument pair, so you can make it a non-deduced context, so that no deduction for it will be attempted.

A common approach to that is to use std::type_identity_t:

template<typename ElementType>
void iterateOver2DVector(std::vector<std::vector<ElementType>> & vec, 
                         std::type_identity_t<std::function<void(ElementType & element)>> function)

std::type_identity_t<T> is an alias for std::type_identity<T>::type which is an alias for T, however since the type T now is left of a :: it is in a non-deduced context.

std::type_identity_t is only available since C 20, but it can be defined easily in previous versions of C :

template<typename T> struct type_identity { using type = T; };
template<typename T> using type_identity_t = typename type_identity<T>::type;

However, in this case std::function is just unnecessary overhead anyway. Simply accept the closure type directly, instead of a std::function:

template<typename ElementType, typename F>
void iterateOver2DVector(std::vector<std::vector<ElementType>> & vec, 
                         F function)

A std::function is only useful if you intend to store the callable without dependence on its specific type e.g. in a class member and even in that case the conversion to std::function can be done when assigning to the member.

  • Related