Я читаю статью 28 по умным указателям Скотта Мейерса Более эффективный C++ и у вас есть следующий вопрос.Удалить неопределенность в вызове функции на неявно преобразованном умном указателе
Полная демонстрация можно найти по адресу: 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
. Мне интересно, каков правильный способ вызова функции.
не отвечает qustion, но 'вернуть SmartPtr (пуанты e); 'Кажется не правильным, вам нужно что-то вроде' std :: week_ptr', чтобы сделать это –
Вы должны посмотреть на стандартные интеллектуальные указатели и как они обеспечивают преобразование (например) из 'std :: shared_ptr' to 'std :: shared_ptr 'когда (и только тогда)' Derived * 'конвертируется в' Base * '. –
Ваш трюк верен, отсутствует код для ваших конструкторов копий. Если у вас есть тот, который принимает non-const ref - вы получите ошибку, о которой вы упомянули, если вы можете просто изменить ref на const в copy ctor, а код будет компилироваться (проверен) –