考虑以下代码:
template<class T>
vector<T> filter(typename vector<T>::iterator begin,
typename vector<T>::iterator end,
bool (*cond)(T a))
{
vector<T> vec;
for (typename vector<T>::iterator it = begin; it != end; it++) {
if (cond(*it)) {
vec.push_back(*it);
}
}
return vec;
}
vector<int> vec = { 1,2,3,4,5,6,7,8,9,10 };
auto another_vec = filter<int>(vec.begin(), vec.end(), [](int a) {return a > 5; });
当我从函数过滤器的调用中删除类型时,代码无法编译,即撰写
时filter(vec.begin(), vec.end(), [](int a) {return a > 5; });
我的问题是,为什么?编译器可以从lambda和迭代器中推断出类型。
我得到的错误是:
错误C2784'std :: vector> 过滤器(vector> :: iterator,vector> :: iterator,bool (__cdecl *)(T))':无法推论'bool的模板参数 (__cdecl *)(T)'来自 'main ::'示例c:\ users \ danii \ documents \ visual Studio 2017 \ projects \ example \ example \ source.cpp 24
我找不到有关此问题的详细信息。 我的猜测是,编译器无法推断内部类型? (例如,不能从 vector 推断 int )。如果是这样,为什么呢?如果没有,情况如何?有什么办法可以解决?
我遇到的另一件事是使用迭代器本身作为模板,例如
template <class T, class iter, class cond>
vector<T> filter(iter begin, iter end, cond c)
编程正确吗?这段代码对我来说有点可疑。
答案 0 :(得分:2)
这是因为lambda类型与预期的函数类型不完全相同,因此模板推导将不起作用。编译器不能同时进行隐式转换和模板推导。如果您使用函数,它将:
bool f(int a) {
return a > 5;
}
int main() {
vector<int> vec = { 1,2,3,4,5,6,7,8,9,10 };
auto another_vec = filter(vec.begin(), vec.end(), f);
return 0;
}
答案 1 :(得分:1)
我的猜测是,编译器无法推断内部类型? (例如,无法从vector推导int)。
是的。这属于non-deduced contexts:
在以下情况下,类型,模板和非类型值 用于撰写P不参与模板参数 推导,而是使用以下模板参数 在其他地方推导或明确指定。如果模板参数是 仅在非推论上下文中使用且未明确指定, 模板参数推导失败。
1)嵌套名称说明符(范围左侧的所有内容) 分辨率运算符::)的类型使用 合格ID:
请注意,没有捕获的lambda表达式(第三个参数)可以隐式转换为函数指针,但是template argument deduction不考虑隐式转换。
类型推导不考虑隐式转换(类型除外) 上面列出的调整项):这是解决过载的工作, 以后会发生。
然后,类型推导在这里失败。
您的修复想法是一个好主意,但是您不需要模板参数T
,该模板参数不能(也不需要)推导。您可以将其更改为:
template<class iter, class cond>
auto filter(iter begin, iter end, cond c)
{
vector<typename std::iterator_traits<iter>::value_type> vec;
for (auto it = begin; it != end; it++) {
if (cond(*it)) {
vec.push_back(*it);
}
}
return vec;
}