在隐式转换后的智能指针上删除函数调用中的歧义



我正在阅读Scott Meyers 更有效的C 的智能指针上的项目28,并有以下问题。

可以在http://ideone.com/akq6c0.

上找到一个完整的演示。

可以将派生的类指针隐式转换为基类指针:

class Base {};
class Derived : public Base {};
void foo(Base* b) { cout << "foo called on Base pointer" << endl;}
Derived *d = new Derived();
foo(d); //No problem

但是,这种隐式转换不能用于智能指针,即SmartPtr<Derived>不能隐式转换为SmartPtr<Base>。因此,我们使用成员模板进行此类转换:

template<typename T>
class SmartPtr {
public:
  //constructors, operator->, etc
  //member template for type conversion
  template<NewType>
  operator SmartPtr<NewType> () {
    return SmartPtr<NewType>(pointee);
  }
private:
  T* pointee;//the raw pointer
};

这几乎可以起作用,但可能会引起歧义:

class Remote {};
class Base : public Remote {};
class Derived : public Base {};
void foo(const SmartPtr<Remote>& p) { cout << "remote" << endl;}
void foo(const SmartPtr<Base>& p) { cout << "base" << endl;}
SmartPtr<Derived> d(new Derived());
foo(d);//compile error: ambiguity

在此示例中,编译器不知道该编译器是否应该将d转换为SmartPtr<Base>SmartPtr<Remote>,尽管对于原始指针Base显然很出色。这本书说

我们能做的最好的是使用成员模板来生成转换功能,然后在歧义结果的情况下使用铸件。

但是,我们在这里如何确切应用?foo(static_cast<SmartPtr<Base>>(d))也不编译。从错误消息中,我可以看出该错误来自SmartPtr的复制构造人中使用非const引用。我想知道做函数调用的正确方法是什么。

//constructors

这是您省略的最重要部分:)

您的演员表是正确的,这一切都取决于您拥有的一组构造函数。如果您有一个非const Ref的人 - 您会收到提到的错误,如果您只能将Ref更改为复制ctor中的const,并且代码将编译。

可能不是很明显,但是当您致电

return SmartPtr<NewType>(pointee);

您正在构建必须接受T*的新SmartPtr<NewType>,而NewTypeT是不同的类型。您很可能只有CTOR接受相同类型的原始指针(即SmartPtr<T>T*X*SmartPtr<X>),因此编译器正在寻找另一个转换CTOR来创建您的新smartptr并找到您的副本CTOR,但无法绑定新值,但它无法绑定新值到非const ref


编辑:

如果您使用的是C 11添加移动CTOR也可以解决您的问题,因为它可以绑定到RVALUE

SmartPtr( SmartPtr<T>&& other): pointee(other.pointee) { other.pointee = nullptr; }

最新更新