Почему auto_ptr не поддерживает op → *()
auto_ptr (shared_ptr также) стараются сделать их использование максимально прозрачным; то есть, в идеале, вы не должны понимать, используете ли вы auto_ptr или реальный указатель на объект. Рассмотрим:
class MyClass
{
public:
void foo() { }
};
MyClass* p = new MyClass;
auto_ptr<MyClass> ap(new MyClassp);
p->foo(); // No notational difference in using real
ap->foo(); // pointers and auto_ptrs
Когда вы пытаетесь вызвать функцию-член через указатель-член, существует разница, поскольку auto_ptr, очевидно, не реализует op → *():
void (MyClass::*memfun)() = &MyClass::foo;
(p->*memfun)(); // OK
(ap->*memfun)(); // Error op->*() missing
(ap.get()->*memfun)(); // OK
Почему нет поддержки op → *() в auto_ptr и как бы реализовать ее (я экспериментировал некоторое время, но в конечном итоге сдался).
Ответы
Ответ 1
Поскольку Лютер указывает на его нетривиальность для реализации - но это возможно.
Вы должны
- используйте шаблоны, чтобы можно было указать тип аргументов
operator->*
- заботиться о возможных классификаторах и многократных функциях с использованием перегрузок
- для указателей функций-членов возвращает объект callabe, который:
- связанный с экземпляром, умный указатель указывает на
- реализует
operator()
с сигнатурой, эквивалентной функции-члену
Игнорируя квалификаторы для мумиона, вот как он мог в основном выглядеть (используя С++ 0x, чтобы избежать ручной репликации):
// pointer to data member:
template<class T, class D>
D& operator->*(std::auto_ptr<T>& p, D T::*mp) {
return (*p).*mp;
}
// pointer to member function:
template<class T, class R, class... Args> struct Callable {
typedef R (T::*MFP)(Args...);
MFP mfp;
T& instance;
Callable(T t, MFP mfp) : instance(t), mfp(mfp) {}
R operator()(Args... a) {
return (instance.*mfp)(a...);
}
};
template<class T, class R, class... Args>
Callable<T, R, Args...>
operator->*(std::auto_ptr<T>& p, R (T::*mfp)(Args...)) {
return Callable<T, R, Args...>(*p, mfp);
}
Но в конце концов, зачем беспокоиться, когда мы могли бы просто использовать функторы, которые в первую очередь связывают указатели на элементы.
Хотя я не могу быть уверен в этом, если вы объедините знания о том, что
- реализация является нетривиальной
- существует простая альтернатива, которая работает так же хорошо (
(*p).*m
)
... его, вероятно, обычно не реализовывают из-за плохого отношения работы, необходимого для получения прибыли, получаемой в результате этой функции.
Ответ 2
реализация → * потребует решения идеальной проблемы пересылки:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2002/n1385.htm
Оператор - > * должен возвращать вызываемый объект с тем же списком параметров, что и объект-указатель на элемент, правильно управляя константами const, volatileness и reference. И тогда ему придется использовать специальные магические полномочия для обработки параметров по умолчанию. Это сложно, подвержено ошибкам, неразрешимо и слишком много времени компилирует, и поскольку указатели на элементы являются сравнительно незначительно популярной функцией С++, они обычно не учитываются при реализации интеллектуальных указателей.
Ответ 3
Возможно, я ошибаюсь, но я думаю, что нет способа перегрузить operator->*
для функции-указателя. Это связано с тем, что p->*memfun
, будучи действительным как часть выражения, рассматривающего его как вызываемый объект, не является правильным выражением в своем собственном праве и не имеет типа. Поэтому для возвращаемого оператора не существует допустимого типа.
Следующее будет работать для указателя на элемент, но попытка использовать его для функции-указателя-члена дает ошибку, "недопустимое использование нестатической функции-члена", с GCC и внутреннюю ошибка компилятора с MSVC.
template <class CLASS, typename MEMBER>
MEMBER& operator->*(std::auto_ptr<CLASS>& p, MEMBER CLASS::*m)
{
return (*p).*m;
}
EDIT: как указывает Георг, вы можете использовать boost::bind
или аналогичный для создания набора перегрузок для функций-членов с фиксированным максимальным количеством аргументов, но до сих пор нет возможности перегрузить оператор для всех возможных членов функции.