【问题标题】:Template parameter inference fails模板参数推断失败
【发布时间】:2018-11-10 08:52:22
【问题描述】:

考虑以下代码:

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> 过滤器(向量>::迭代器,向量>::迭代器,布尔 (__cdecl *)(T))': 无法推断出'bool'的模板参数 (__cdecl *)(T)' 来自 'main::' 示例 c:\users\danii\documents\visual 工作室 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)

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

【问题讨论】:

  • 模板的迭代器方法很好 - 还有一个很大的优势:您也可以将您的函数与其他容器一起使用,例如。 G。 std::list, std::deque, ... 将条件作为模板也提供了更大的灵活性;并非所有 lambda 都可以转换为函数(如果闭包不为空),它也适用于经典(C++11 之前)仿函数。

标签: c++ templates template-argument-deduction


【解决方案1】:

这是因为 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;
}

【讨论】:

  • 另外,lambda 可以显式强制转换为函数(在给定的情况下可能,因为它没有闭包)。
【解决方案2】:

我的猜测是,编译器不能推断内部类型? (例如不能从向量中推断出 int)。

是的。这属于non-deduced contexts

在以下情况下,类型、模板和非类型值 用于组成 P 不参与模板参数 推论,而是使用模板参数 在别处推断或明确指定。如果模板参数是 仅在非推导上下文中使用且未明确指定, 模板参数推导失败。

1) 嵌套名称说明符(范围左侧的所有内容 使用 a 指定的类型的解析运算符 ::) 合格的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;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-26
    • 2012-12-06
    • 1970-01-01
    相关资源
    最近更新 更多