在模板化链表中调用查找没有匹配函数

时间:2017-08-10 00:28:54

标签: c++ c++11 templates generics

编译器错误"没有用于呼叫"的匹配功能在我的例子中,链接列表中的查找功能。

为什么会出现此错误?

功能

template<class T>
int find(std::shared_ptr<Node<T>> ptr, T val) {
    int pos(0);
    while (ptr) {
        if (ptr->val == val)
            return pos;
        else {
            ptr = ptr->next;
            pos++;
        }
    }
    return -1; // Not found
}

调用

std::cout << "Pos: " << find(myFloat, 9.83) << std::endl;

myFloatshared_ptr,是浮点列表的根节点,已成功填充如下:

浮动的链接列表

2.5 ⟹ 3.7 ⟹ 4.8 ⟹ 7.93 ⟹ 0.96 ⟹ 9.83 ⟹ 7.45

STRUCT

template<class T>
struct Node {
    Node(T k):val(k){}
    T val;
    std::shared_ptr<Node<T>> next = nullptr;
};

错误

  

没有匹配功能可以调用&#39;查找&#39;

myFloat定义

std::shared_ptr<Node<float>> myFloat = { std::make_shared<Node<float>>(0.) };

1 个答案:

答案 0 :(得分:3)

由于您没有向find提供任何显式模板参数(如find<float>(myFloat, 9.83)中所述),编译器必须从函数参数中推导出模板参数T

在模板参数推导期间,函数参数类型中模板参数的每次出现都在推导上下文或非推导上下文中。在您的情况下,两者都被视为推断上下文。为推导的上下文中的模板参数的每个外观确定类型或值。

myFloat的类型为std::shared_ptr<Node<float>>,第一个函数参数的类型为std::shared_ptr<Node<T>>,因此T推导为float

9.83的类型为double,第二个函数参数的类型为T,因此T推断为双倍。

由于模板参数T被推断为两种不同的类型,因此总体扣除失败!当多次推导出相同的模板参数时,所有结果必须相同。

那么你能做些什么才能让它成功呢?

令人不快的解决方案是单独留下模板并要求呼叫者小心使用它。 find<float>(myFloat, 9.83)可以通过显式提供模板参数来工作。 find(myFloat, 9.83f)可以通过更改第二个函数参数的类型来工作。但最好让模板更灵活,更友好。

一个简单的解决方法是只使用两个不同的模板参数。

template<class T, class U>
int find(std::shared_ptr<Node<T>> ptr, U val);

然后该函数只需要==运算符适用于TU类型。

或者如果您希望将第二个函数参数隐式转换为Node中使用的类型,您可以有意将第二次使用T转换为非推导的上下文:

template <typename T>
struct identity {
    using type = T;
};

template<class T>
int find(std::shared_ptr<Node<T>> ptr,
         typename identity<T>::type val);

通过显示::的左侧,第二个T现在是非推断的上下文,因此表达式find(myFloat, 9.83)将仅从第一个参数中推导出T,从而得到在T=float中,然后替换为模板函数声明。 typename identity<float>::typefloat发送,因此会有double文字9.83隐式转换为float以调用该函数。