[英]C++: template function taking function which takes another function which takes reference to template type as parameter
考虑以下代码
struct S
{
unsigned u;
float f;
S(unsigned u0, float f0) : u(u0), f(f0) {}
};
template<typename T> bool contains(std::vector<T> vec, T elem, bool equivalent(const T&, const T&))
{
// some implementation
}
int main() {
std::vector<S> vec{{15, 17.8}};
std::cout << contains(vec, S(15,159.48), [](S& a, S& b) -> bool {return a.u == b.u;}) << std::endl;
}
为什么此代码无法编译以及如何修复? 我相信从上下文中可以清楚 function 包含的内容应该做什么。
我收到以下错误:
main.cpp:32:18: error: no matching function for call to 'contains'
std::cout << contains(vec, S(15,159.48), [](S& a, S& b) -> bool {return a.u == b.u;}) << std::endl;
^~~~~~~~
main.cpp:14:27: note: candidate template ignored: could not match 'bool (*)(const T &, const T &)' against '(lambda at main.cpp:32:46)'
template<typename T> bool contains(std::vector<T> vec, T elem, bool equivalent(const T&, const T&))
它可以通过为第三个参数添加std::type_identity_t
来修复,这样它就不会参与推导模板参数:
#include <iostream>
#include <vector>
#include <type_traits>
struct S
{
unsigned u;
float f;
S(unsigned u0, float f0) : u(u0), f(f0) {}
};
template<typename T> bool contains(std::vector<T> vec, T elem, std::type_identity_t<bool (*)(const T&, const T&)> equivalent)
// Can also use following synaxis: std::type_identity_t<bool(const T&, const T&)> *equivalent
{
// some implementation
}
int main() {
std::vector<S> vec{{15, 17.8}};
std::cout << contains(vec, S(15,159.48), [](const S& a, const S& b) -> bool {return a.u == b.u;}) << std::endl;
}
如果你没有 C++20,你可以很容易地自己定义它:
template< class T >
struct type_identity {
using type = T;
};
template< class T >
using type_identity_t = typename type_identity<T>::type;
为什么此代码无法编译以及如何修复? 我相信从上下文中可以清楚 function 包含的内容应该做什么。
问题是 lambda 不是 function; 它是一个 object,里面有一个 function ( operator()
)。
在你的情况下,假设 lambda 没有捕获,可以转换为 function 指针。
那么为什么编译器不将 lambda 转换为 function 指针呢? 还有一个问题; 一种先有鸡还是先有蛋的问题: T
模板类型的推导。
模板contains()
template <typename T>
bool contains(std::vector<T> vec, T elem, bool equivalent(const T&, const T&))
对所有 arguments 使用T
类型:对于vec
,对于elem
和对于equivalent
。 所以编译器尝试从所有 arguments 中推导出T
鉴于编译器试图推导T
也形成第三个参数(鸡和蛋的问题)不能从 lambda 推导T
因为 lambda 不是 function 指针并且不能将 lambda 转换为 function 指针因为不t 从 lambda 推导出T
我看到四种可能的解决方案。
contains()
,使用std::type_identity
,如下template <typename T>
bool contains (std::vector<T> vec, T elem, std::type_identity_t<bool(*)(const T&, const T&)> equivalent)
或者也如下
template<typename T>
bool contains (std::vector<T> vec, T elem, std::type_identity_t<bool(const T&, const T&)> equivalent)
通过这种方式,您可以禁止从equivalent
推导T
,从vec
和elem
推导(作为T
),因此编译器可以将S
转换为 function 或 function 指针。
template <typename T, typename F>
bool contains (std::vector<T> vec, T elem, F equivalent)
这种方式equivalent
可以直接是一个lambda,不用转换。 所以你也可以接受捕获 lambda (不能转换为函数)。 缺点是你不能强制那个equivalent
接收两个T const &
arguments,但是使用equivalent
应该足以检查不一致
contains()
function,但您可以更改调用,使用 lambda 前面的+
运算符,强制将 lambda 转换为 function 指针// .........................V the '+' operator force the conversion
contains(vec, S(15,159.48), +[](S const & a, S const & b)...
但请记住定义 lambda 接收两个S const &
,如 function 定义,而不是两个S &
,如您的示例。
通过这种方式,编译器接收到一个 function 指针,也可以从第三个参数正确地推断出T
的S
。
contains()
function 并在调用中显式显示模板类型// .....VVV S type is explicit, no type deduction take place
contains<S>(vec, S(15,159.48), [](S const & a, S const & b)...
这样调用就明确了S
类型,对于T
。 所以没有类型推导发生,所以编译器可以将 lambda 转换为 function
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.