I have the following templated method:
auto clusters = std::vector<std::pair<std::vector<long>, math::Vector3f>>
template<class T>
void eraserFunction(std::vector<T>& array, std::function<int(const T&, const T&)> func)
{
}
And I have a function that looks like
auto comp1 = [&](
const std::pair<std::vector<long>, math::Vector3f>& n1,
const std::pair<std::vector<long>, math::Vector3f>& n2
) -> int {
return 0;
};
math::eraserFunction(clusters, comp1);
However, I get a syntax error saying:
116 | void eraserFunction(std::vector<T>& array, std::function<int(const T&, const T&)> func)
| ^~~~~~~~~~~~~~
core.hpp:116:6: note: template argument deduction/substitution failed:
geom.cpp:593:23: note: 'math::method(const at::Tensor&, const at::Tensor&, int, float, int, int, float)::<lambda(const std::pair<std::vector<long int>, Eigen::Matrix<float, 3, 1> >&, const std::pair<std::vector<long int>, Eigen::Matrix<float, 3, 1> >&)>' is not derived from 'std::function<int(const T&, const T&)>'
593 | math::eraserFunction(clusters, comp1);
CodePudding user response:
The function call tries to deduce T
from both the first and second function parameter.
It will correctly deduce T
from the first parameter, but fail to deduce it from the second parameter, because the second function argument is a lambda type, not a std::function
type.
If deduction isn't possible from all parameters that are deduced context, deduction fails.
You don't really need deduction from the second parameter/argument here, since T
should be fully determined by the first argument. So you can make the second parameter a non-deduced context, for example by using std::type_identity
:
void eraserFunction(std::vector<T>& array, std::type_identity_t<std::function<int(const T&, const T&)>> func)
This requires C 20, but can be implemented easily in user code as well if you are limited to C 11:
template<typename T>
struct type_identity { using type = T; };
and then
void eraserFunction(std::vector<T>& array, typename type_identity<std::function<int(const T&, const T&)>>::type func)
std::identity_type_t<T>
is a type alias for std::identity_type<T>::type
. Everything left to the scope resolution operator ::
is a non-deduced context, which is why that works.
If you don't have any particular reason to use std::function
here, you can also just take any callable type as second template argument:
template<class T, class F>
void eraserFunction(std::vector<T>& array, F func)
This can be called with a lambda, function pointer, std::function
, etc. as argument. If the argument is not callable with the expected types, it will cause an error on instantiation of the function body containing the call. You can use SFINAE or since C 20 a type constraint to enforce this already at overload resolution time.