Почему auto_ptr не поддерживает op -> * () - PullRequest
17 голосов
/ 17 июля 2010

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

Почему в auto_ptr нет поддержки op -> * () и как ее реализовать (я экспериментировал некоторое время, но в итоге отказался).

Ответы [ 3 ]

8 голосов
/ 17 июля 2010

Как указывает Лютер, его нетривиально реализовать - но это возможно.

Вы должны

  1. использовать шаблоны, чтобы можно было определить тип аргументов operator->*
  2. позаботится о возможных квалификаторах и множественных функциях с использованием перегрузок
  3. для указателей на функции-члены возвращают объект callabe, который:
    • привязанный к экземпляру, смарт-указатель указывает на
    • реализует operator() с сигнатурой, эквивалентной функции-члену

Игнорируя квалификаторы для момента, вот как он может выглядеть (используя C ++ 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)

... это, вероятно, обычно не реализуется из-за плохого соотношения требуемой работы и выгоды, получаемой от этой функции.

4 голосов
/ 17 июля 2010

внедрение -> * потребует решения идеальной задачи пересылки:

http://www.open -std.org / ОТК1 / SC22 / wg21 / документы / документы / 2002 / n1385.htm

operator -> * должен будет возвращать вызываемый объект с тем же списком параметров, что и объект указатель на член, правильно обрабатывая типы const, volatile и reference. И тогда ему придется использовать специальные магические силы для обработки параметров по умолчанию. Это сложно, подвержено ошибкам, неразрешимо и требует слишком много времени компиляции, и поскольку указатели на члены являются сравнительно незначительной популярностью в C ++, они, как правило, не учитываются в реализации интеллектуальных указателей.

0 голосов
/ 17 июля 2010

Я могу ошибаться, но я думаю, что нет способа перегрузить operator->* для функции указателя на член. Это потому, что p->*memfun, хотя и является действительным как часть выражения, которое обрабатывает его как вызываемый объект, само по себе не является допустимым выражением и не имеет типа. Поэтому для оператора не существует допустимого типа для возврата.

Следующее будет работать для указателя на член, но попытка использовать его для указателя на функцию-члена выдает ошибку, «недопустимое использование нестатической функции-члена» с GCC и внутреннюю ошибка компилятора с MSVC.

template <class CLASS, typename MEMBER>
MEMBER& operator->*(std::auto_ptr<CLASS>& p, MEMBER CLASS::*m)
{
    return (*p).*m;
}

РЕДАКТИРОВАТЬ: как указывает ответ Георга, вы можете использовать boost::bind или аналогичный для создания набора перегрузок для функций-членов до фиксированного максимального количества аргументов, но все еще нет способа перегрузить оператор для всех возможных членов функции.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...