C++ 模板成员转换运算符中存在编译错误

C++ 模板成员转换运算符中存在编译错误,c++,compiler-errors,auto-ptr,function-templates,C++,Compiler Errors,Auto Ptr,Function Templates,我试图在一个类中编写一个转换运算符函数模板,但遇到了一些我不完全理解的编译错误 class ABC { }; class BBC:public ABC { }; template <class T> class TestPtr { public: TestPtr(T* ptr=0) : _pointee(ptr) { } TestPtr(TestPtr& rhs) {

我试图在一个类中编写一个转换运算符函数模板,但遇到了一些我不完全理解的编译错误

class ABC { };

class BBC:public ABC { };

template <class T>
class TestPtr
{
    public:
        TestPtr(T* ptr=0)
            : _pointee(ptr)
        {   }

        TestPtr(TestPtr& rhs)
        {
            this->_pointee = rhs._pointee;
            rhs._pointee= 0;
        }

        template <class U> operator TestPtr<U>();

    private:
        T* _pointee;
};

template <class T> template <class U>
TestPtr<T>::operator TestPtr<U>()
{
    return TestPtr<U>(this->_pointee);   // if this line is changed to 
    //TestPtr<U> x(this->_pointee);      // these commented lines, the 
    //return x;                          // compiler is happy
}

void foo (const TestPtr<ABC>& pmp)
{  }

int main() {
    TestPtr<BBC> tbc(new BBC());
    foo(tbc);
}
类ABC{};
BBC类:公共ABC{};
模板
类TestPtr
{
公众:
TestPtr(T*ptr=0)
:_pointee(ptr)
{   }
测试PTR(测试PTR和rhs)
{
此->\u pointee=rhs.\u pointee;
rhs._pointee=0;
}
模板操作符TestPtr();
私人:
T*_pointee;
};
模板
TestPtr::运算符TestPtr()
{
返回TestPtr(this->_pointee);//如果此行更改为
//testptrx(this->_pointee);//这些注释行
//return x;//编译器很高兴
}
无效foo(施工测试PTR和pmp)
{  }
int main(){
TestPtr tbc(新BBC());
foo(待定);
}
上述代码导致以下错误

TestPtr.cpp: In member function ‘TestPtr<T>::operator TestPtr<U>() [with U = ABC, T = BBC]’:
TestPtr.cpp:38:9:   instantiated from here
TestPtr.cpp:28:34: error: no matching function for call to ‘TestPtr<ABC>::TestPtr(TestPtr<ABC>)’
TestPtr.cpp:28:34: note: candidates are:
TestPtr.cpp:13:3: note: TestPtr<T>::TestPtr(TestPtr<T>&) [with T = ABC, TestPtr<T> = TestPtr<ABC>]
TestPtr.cpp:13:3: note:   no known conversion for argument 1 from ‘TestPtr<ABC>’ to ‘TestPtr<ABC>&’
TestPtr.cpp:9:3: note: TestPtr<T>::TestPtr(T*) [with T = ABC]
TestPtr.cpp:9:3: note:   no known conversion for argument 1 from ‘TestPtr<ABC>’ to ‘ABC*’
TestPtr.cpp:在成员函数“TestPtr::operator TestPtr()[with U=ABC,T=BBC]”中:
TestPtr.cpp:38:9:从此处实例化
TestPtr.cpp:28:34:错误:对“TestPtr::TestPtr(TestPtr)”的调用没有匹配的函数
TestPtr.cpp:28:34:注:候选人为:
TestPtr.cpp:13:3:注意:TestPtr::TestPtr(TestPtr&)[带T=ABC,TestPtr=TestPtr]
TestPtr.cpp:13:3:注意:参数1没有从“TestPtr”到“TestPtr&”的已知转换
TestPtr.cpp:9:3:note:TestPtr::TestPtr(T*)[带T=ABC]
TestPtr.cpp:9:3:注意:参数1没有从“TestPtr”到“ABC*”的已知转换
现在让我感到困惑的是,编译器试图在return语句中选择
TestPtr::TestPtr(TestPtr)
而不是
TestPtr::TestPtr(ABC*)
。但是,如果我首先使用预期的构造函数创建一个变量,然后返回该值,它就可以正常工作。我还显式地使用了T*构造函数,但没有效果


我用g++和clang++都试过,结果相似。有人能解释一下这里发生了什么吗?

问题在于您的复制构造函数。其参数是一个
TestPtr&
(非常量参考):

非常量引用无法绑定到右值表达式
TestPtr(this->_pointee)
是一个创建临时对象的右值表达式。当您试图直接返回此对象时,必须制作副本。因此,当编译器无法调用复制构造函数时,会出现此错误

通常情况下,解决方案是让副本构造函数获取常量引用。然而,在这种情况下,解决方案有点棘手;您将需要执行与
std::auto_ptr
类似的操作。我在回答问题时描述了它的肮脏伎俩

可选地,如果您使用的是最近的C++编译器,只需要支持支持R值引用的编译器,可以通过提供用户声明的移动构造函数(<代码> TESTPtR(TestPt&&)<代码>)和通过抑制复制构造函数来使您的类可移动但不可复制。(如果编译器支持已删除的成员函数,则声明它为

=delete
,或者声明它为private而不定义它)



还要注意,您必须提供一个用户声明的复制分配运算符。(或者,如果您决定只进行类型移动,则需要提供一个用户声明的移动分配运算符并抑制隐式复制分配运算符,再次使用
=delete
或通过声明而不定义它。)

在复制构造函数中,出于某种原因,您坚持将源指针归零

TestPtr(TestPtr& rhs)
{
  this->_pointee = rhs._pointee;
  rhs._pointee= 0;
}
你为什么这么做

由于您坚持将
rhs
归零,因此不能将参数声明为
const TestPtr&rhs
,这反过来会破坏您的代码,正如James解释的那样

我看不出有任何理由将源指针归零。只要这样做就行了

TestPtr(const TestPtr& rhs) : _pointee(rhs._pointee)
  {}
它应该会起作用

我怀疑您使用了
std::auto_ptr
作为灵感,并在它的复制例程中看到了类似的东西。但是,在
std::auto_ptr
中,源指针被调零,因为
std::auto_ptr
获取它指向的对象的所有权,并在复制时转移该所有权。对所有权的需要管理是由以下事实决定的:
std::auto_ptr
不仅指向对象,还试图自动销毁它们


您的指针不试图破坏任何东西。它不需要获取指向对象的所有权。因此,在复制指针时,您不需要将源归零。

实际上,James提到了我希望实现的确切用例。我需要类中t*的所有权语义,这意味着rhs需要强制霍克:嗯,从你的问题上看,这不是很明显。那我为什么还要做
rhs.\u pointee=0;
?我只是在这里发布了一部分代码,因为我认为最好尽可能具体地发布。@hawk:嗯,如果我知道你为什么这么做,我就不会在我的回答中问这个问题了,是吗?谢谢你的回复正确的答案。我最近开始学习C++,不确定如何理解无数的编译器错误信息。有没有办法提高我在这方面的知识?
TestPtr(const TestPtr& rhs) : _pointee(rhs._pointee)
  {}