Подтвердить что ты не робот

Почему 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 и как бы реализовать ее (я экспериментировал некоторое время, но в конечном итоге сдался).

4b9b3361

Ответ 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 или аналогичный для создания набора перегрузок для функций-членов с фиксированным максимальным количеством аргументов, но до сих пор нет возможности перегрузить оператор для всех возможных членов функции.