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.