c++ - 模板成员转换运算符编译错误

标签 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)
        {
            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);
}

以上代码导致如下错误

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<ABC>::TestPtr(TestPtr<ABC>)而不是 TestPtr<ABC>::TestPtr(ABC *)在返回声明中。但是,如果我先用预期的构造函数创建一个变量,然后返回它工作正常的值。我还使 T* 构造函数显式化,但无济于事。

我已经尝试过 g++ 和 clang++,结果相似。有人可以解释一下这里发生了什么吗?

最佳答案

问题出在你的复制构造函数上。它的参数是TestPtr& (非常量引用):

TestPtr(TestPtr& rhs)

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

通常解决方案是让您的复制构造函数采用 const 引用。但是,在这种情况下,解决方案有点棘手;你会想做类似于 std::auto_ptr 的事情做。我在对 "How could one implement std::auto_ptr's copy constructor?" 的回答中描述了它的卑鄙伎俩。

或者,如果您使用的是最新的 C++ 编译器并且只需要支持支持右值引用的编译器,您可以通过提供用户声明的移动构造函数 (TestPtr(TestPtr&&)) 并禁止复制来使您的类可移动但不可复制构造函数(声明它 =delete 如果你的编译器支持删除的成员函数,或者声明它私有(private)而不定义它)。


另请注意,您必须提供用户声明的复制赋值运算符。 (或者,如果您决定使该类型只能移动,您将需要提供一个用户声明的移动赋值运算符并禁止隐式复制赋值运算符,再次使用 = delete 或通过声明而不定义它。)

关于c++ - 模板成员转换运算符编译错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10255768/

相关文章:

c++ - 映射/设置迭代器不可解除(C++)-调试声明失败?

c++ - 按值传递的 auto_ptr 类型的误导性性能警告

c++ - 关于 auto_ptr 的问题

c++ - 重写模板方法

java - 使用Gradle编译Android项目时出现"Error: cannot find symbol"

C++ 模板不接受迭代器

c# - 写入文本文件给我错误

c++ - 在动态分配的数组上使用 auto_ptr 的正确方法是什么?

c++ - 即使我知道我将使用哪个泛型,转发声明模板类是否安全?

c++ - 实现整数除法舍入的正确方法是什么?