Как перегрузить оператор -> * в C ++ - PullRequest
2 голосов
/ 22 марта 2011

Есть ли способ перегрузить ->* для использования с объектом, похожим на смарт-указатель? Ниже то, что я хотел бы сделать. Для простоты я не использую шаблоны (я вернусь к этому, как только у меня будет работать для одного фиксированного класса). Я могу заставить его работать с указателями на элементы данных, но я не могу сделать это правильно для указателей на функции-члены. В настоящее время я готов согласиться на перегрузку, которая работает только для функций-членов (а не для членов-данных). Я даже готов согласиться на перегрузку, которая принимает указатели на функции-члены только с одним фиксированным прототипом (таким как void func()).

struct MyObject
{
   void MyMethod() {}
};

struct MySmartPtr {
   MyObject *p;

   // What should the prototype and function body be?
   // ??? operator->*(????) { ???? }
};

void MyFunc()
{
   MyObject obj;
   MySmartPtr obj_ptr;
   obj_ptr.p = &obj;
   void (MyObject::* member_func_ptr)() = &MyObject::MyMethod;

   // Now call obj.MyMethod() through the "smart pointer"
   (obj_ptr->*member_func_ptr)();
}

Пожалуйста, не предлагайте мне обходные пути (например, перегрузка * и выполнение (*obj_ptr.*member_func_ptr)()). Я хочу, чтобы ->* работал, как указано во фрагменте кода.

Ответы [ 3 ]

12 голосов
/ 22 марта 2011

Взгляните на эту статью Скотта Мейерса.Это довольно старый, но единственный ресурс, обсуждающий перегрузку ->*, о котором я знаю.

Обратите внимание, что типы итераторов и интеллектуальных указателей стандартной библиотеки не перегружаются ->*.Я не знаю причин, но я подозреваю, что это потому, что этот оператор редко когда-либо использовался, это создает много хлопот, и его легко обойти.В любом случае, поскольку стандартная библиотека не поддерживает ее, ваши пользователи также не ожидают, что она будет работать.

1 голос
/ 22 марта 2011

http://codepad.org/yl3Ghwab

#include <stdio.h>

struct OBJ {
  typedef void (OBJ::*Met)(void);
  void met( void ) {
    printf( "Method call!\n" );
  }
};

struct POBJ {
  OBJ* p;
  typedef void (*fun)(void);
  static void nop( void ) {}
  fun operator->*( OBJ::Met m ) {
    printf( "operator ->* !\n" );
//    return fun(p->*m); // works in gcc
    (p->*m)();
    return nop;
  }
};

int main( void ) {
  OBJ obj;
  OBJ* pobj = &obj;
  POBJ p; p.p = &obj;
  OBJ::Met met = &OBJ::met;
  (pobj->*met)();
  (p->*met)();
}

См. http://en.wikipedia.org/wiki/Operators_in_C_and_C%2B%2B для прототипов

0 голосов
/ 22 марта 2011

Я сделаю это с C ++ 0x: шаблоны с переменными значениями, привязка и функции. Я думаю, должно быть возможно портировать его для повышения:

#include <iostream>                                                             
#include <functional>                                                           

struct S
{       
  void f()
  {
    std::cout << __PRETTY_FUNCTION__ << std::endl;
  }
};

template<class C>
struct PMFSmartPtr
{
  C *p;
  template<typename C1, typename R, typename... P>
  std::function<R(P...)> operator->*(R (C1::*pmf)(P...))
  {
    std::cout << __PRETTY_FUNCTION__ << std::endl;
    return(std::function<R(P...)>(std::bind(pmf, p)));
  }
};

int main()
{
  PMFSmartPtr<S> x;
  void (S::*pmf)() = &S::f;
  (x->*pmf)();
  return(0);
}

Пробовал на g ++ 4.4.4 и работает для функций, не принимающих никаких аргументов, для компиляции функции-члена с 1 аргументом происходит сбой, но я не знаю, является ли это моей ошибкой, проблемой компилятора или libstdc ++ ...

...