C++ 编译器声明调用没有匹配函数,即使原型中有一个

C++ 编译器声明调用没有匹配函数,即使原型中有一个,c++,C++,我试图实现一个二进制搜索树类,但是编译器抛出了错误。bstNode.h文件位于以下位置: template <class Item, class Key> class bstNode { public: bstNode(); bstNode(const Item& init_data, const Key& init_key, bstNode<Item, Key> *init_left, bstNode<Item, Key> *

我试图实现一个二进制搜索树类,但是编译器抛出了错误。bstNode.h文件位于以下位置:

template <class Item, class Key>
class bstNode
{
public:
    bstNode();
    bstNode(const Item& init_data, const Key& init_key, bstNode<Item, Key> *init_left, bstNode<Item, Key> *init_right);
    ~bstNode();
    bstNode<Item, Key>* tree_copy(const bstNode<Item, Key>*& root);
private:
    Item data;
    Key key;
    bstNode* left;
    bstNode* right;
};

    template <class Item, class Key>
    //line 83 in the original code is below
bstNode<Item, Key>* bstNode<Item, Key>::tree_copy(const bstNode<Item, Key>*& root)
{
    bstNode<Item, Key>* l_ptr;
    bstNode<Item, Key>* r_ptr;
    if (root == NULL) return NULL;
    l_ptr = tree_copy(root -> left());
    r_ptr = tree_copy(root -> right());
    return new bstNode<Item, Key> (root -> data(), l_ptr, r_ptr);
}
.h文件在主函数为空的情况下编译得很好,但是当我在bstNode.cxx中使用以下代码位进行尝试时,它崩溃了,并给出了一个错误。代码是:

    #include <cstddef>
#include <algorithm>
#include <math.h>
#include <iostream>
#include "bstNode.h"

using namespace std;

int main()
{
    bstNode<int, size_t>* root_ptr = NULL;
    bstNode<int, size_t>* copy_root_ptr = root_ptr -> tree_copy(root_ptr);
    return 0;
}
错误是:

bstNode.cxx: In function ‘int main()’:
bstNode.cxx:14: error: no matching function for call to ‘bstNode<int, long unsigned int>::tree_copy(bstNode<int, long unsigned int>*&)’
bstNode.h:83: note: candidates are: bstNode<Item, Key>* bstNode<Item, Key>::tree_copy(const bstNode<Item, Key>*&) [with Item = int, Key = long unsigned int]
原型与函数的实现完全相同,没有bstNode::所以我不确定发生了什么。我正在使用g++编译器。有什么想法吗?非常感谢,谢谢


编辑:我减少了代码,试图突出问题。

原型不完全相同,因为存在常量差异。声明是

 bstNode<Item, Key>* tree_copy(const bstNode<Item, Key>*& root);
引用常量指针,而您将其称为

 bstNode<int, size_t>* root_ptr;
 tree_copy(root_ptr);

所以它得到了对非常量指针的引用。虽然可以将foo*传递给接受常数foo*的对象,但不能通过引用接受常数foo*的对象来传递foo*&。

原型并不完全相同,因为存在常数差异。声明是

 bstNode<Item, Key>* tree_copy(const bstNode<Item, Key>*& root);
引用常量指针,而您将其称为

 bstNode<int, size_t>* root_ptr;
 tree_copy(root_ptr);

所以它得到了对非常量指针的引用。虽然可以将foo*传递给接受常量foo*的对象,但不能通过引用接受常量foo*的对象来传递foo*。

编译器在大多数情况下拒绝代码是正确的。问题是没有从T*&到const T*&的转换,因此无法使用现有函数

为什么这种转变不存在

这种转换不存在的原因是它会破坏常量的正确性。考虑这个例子:

const int k = 10;
void f( const int*& kp ) {
   kp = &k;                 // Fine, the pointer promises not to change the object
}
int main() {
   int *p; 
   f( p );                 // Does not compile, but assume it would
                           // after the call, p points to k
   *p = 20;                // Modifying a constant!!!!
                           //    p never promised not to change the pointee
}
现在,一个可能的解决方案是向签名添加更多常量,因为您不需要修改传递给函数的指针:

bstNode<Item, Key>* tree_copy(const bstNode<Item, Key>* const & root);
这样做会阻止代码更改指针,这就是上面示例中的问题。但是,如果你真的想一想

为什么首先要传递对指针的引用


指针的复制成本很低,因此通过const&传递它们没有多大意义,而且由于您不需要函数来更改正在传递的指针,通过值传递将是正确的,而且可能更有效。

编译器在大多数情况下拒绝代码是正确的。问题是没有从T*&到const T*&的转换,因此无法使用现有函数

为什么这种转变不存在

这种转换不存在的原因是它会破坏常量的正确性。考虑这个例子:

const int k = 10;
void f( const int*& kp ) {
   kp = &k;                 // Fine, the pointer promises not to change the object
}
int main() {
   int *p; 
   f( p );                 // Does not compile, but assume it would
                           // after the call, p points to k
   *p = 20;                // Modifying a constant!!!!
                           //    p never promised not to change the pointee
}
现在,一个可能的解决方案是向签名添加更多常量,因为您不需要修改传递给函数的指针:

bstNode<Item, Key>* tree_copy(const bstNode<Item, Key>* const & root);
这样做会阻止代码更改指针,这就是上面示例中的问题。但是,如果你真的想一想

为什么首先要传递对指针的引用


指针的复制成本很低,因此通过const&传递它们没有多大意义,而且由于您不需要函数来更改正在传递的指针,因此通过值传递将是正确的,并且可能更有效。

如果您能够隔离问题,这将对您和我们都有帮助。请将您的程序缩减为仍然显示错误的最小完整程序。看见对指针的引用也是有效的。如果你能找出问题,这将有助于你和我们。请将您的程序缩减为仍然显示错误的最小完整程序。看见对指针也是有效的。啊,谢谢,一定是这样。我想我还是把推荐信拿出来吧。没有必要,只是因为老师想要。当他给我们分配任务时,我非常困惑,因为如果它是常量且无法修改,那么将其作为参考传递又有什么意义呢?我想编译人员同意了D@vanchagreen:注意,在const T*&中,指针不是const,而是指向const T的可变指针。如果将const重写到右侧,可能会有所帮助:const T*&相当于T const*&,而不是T*const&引用指向非const tVancAgreen的const指针,如果大卫的答案或我的答案解决了问题——听起来他们已经解决了——那么你应该接受其中一个。我认为David的答案要好一点,尽管我的目前拥有更多的投票权,但如果您碰巧喜欢,您可以接受我的答案:-。啊,对不起,我是堆栈溢出新手D@GarethMcCaughan不幸的是,我不能修改老师的定义。我不能在不使函数本身为常量的情况下将常量t*&传递到函数中,我不能这样做,因为我不能修改定义。有什么建议吗?啊,谢谢,一定是这样。我想我还是把推荐信拿出来吧。没有必要,只是因为老师想要。伊娃
当他给我们分配任务时,他很困惑,因为如果它是常量并且不能修改,那么把它作为参考传递又有什么意义呢?我想编译人员同意了D@vanchagreen:注意,在const T*&中,指针不是const,而是指向const T的可变指针。如果将const重写到右侧,可能会有所帮助:const T*&相当于T const*&,而不是T*const&引用指向非const tVancAgreen的const指针,如果大卫的答案或我的答案解决了问题——听起来他们已经解决了——那么你应该接受其中一个。我认为David的答案要好一点,尽管我的目前拥有更多的投票权,但如果您碰巧喜欢,您可以接受我的答案:-。啊,对不起,我是堆栈溢出新手D@GarethMcCaughan不幸的是,我不能修改老师的定义。我不能在不使函数本身为常量的情况下将常量t*&传递到函数中,我不能这样做,因为我不能修改定义。有什么建议吗?就这样!非常感谢。不幸的是,我不能修改老师的定义。我不能在不使函数本身为常量的情况下将常量t*&传递到函数中,我不能这样做,因为我不能修改定义。有什么建议吗?就这样!非常感谢。不幸的是,我不能修改老师的定义。我不能在不使函数本身为常量的情况下将常量t*&传递到函数中,我不能这样做,因为我不能修改定义。有什么建议吗?