模板参数推断失败

时间:2018-11-10 08:52:22

标签: c++ templates template-deduction

考虑以下代码:

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)

编程正确吗?这段代码对我来说有点可疑。

2 个答案:

答案 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;
}