Как определить указатель на метод, который возвращает указатель на метод?

В основном у меня есть следующий класс:

class StateMachine {
...
StateMethod stateA();
StateMethod stateB();
...
};

Методы stateA () и stateB () должны иметь возможность возвращать указатели на stateA () и stateB (). Как набрать StateMethod?

На мой взгляд, эта проблема намного сложнее, чем кажется на первый взгляд. Есть много способов решить эту проблему, если вы хотите нарушить полную безопасность типов, но в остальном ... вау.

Chris Jester-Young 02.10.2008 09:37
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
9
1
6 940
5
Перейти к ответу Данный вопрос помечен как решенный

Ответы 5

Моя философия - не использовать необработанные указатели на функции-члены. Я даже не знаю, как делать то, что вы хотите, используя typedef необработанного указателя, синтаксис настолько ужасен. Мне нравится использовать boost :: function.

Это почти определенно неверно:

class X
{
  public:
    typedef const boost::function0<Method> Method;

    // some kind of mutually recursive state machine
    Method stateA()
    { return boost::bind(&X::stateB, this); }
    Method stateB()
    { return boost::bind(&X::stateA, this); }
};

Эта проблема определенно намного сложнее, чем кажется на первый взгляд

Хех, я видел твой предыдущий ответ. Это, вероятно, лучший компромисс; Я обсуждал это в IRC и пришел к выводу, что typedef, ссылающийся на самого себя, вероятно, является «слишком сложной» проблемой.

Chris Jester-Young 02.10.2008 09:29

Хотя, во внутреннем boost :: function0, разве вам не нужно указывать возвращаемый тип и снова использовать рекурсию?

Chris Jester-Young 02.10.2008 09:30

Может быть, я не сижу за компилятором

1800 INFORMATION 02.10.2008 09:32

Звучит как идеальная работа для комбинатора Y, написанного на языке метапрограммирования шаблонов.

1800 INFORMATION 02.10.2008 09:33

@ 1800 ИНФОРМАЦИЯ: да, моя первая мысль была "ну, я просто напишу Y Combinator на typedefs ... о, боже. :("

Jacob Krall 02.10.2008 09:58

Обновлено: njsf доказал, что я ошибаюсь. Однако вам может показаться, что статическое приведение проще поддерживать, поэтому остальное я оставлю здесь.

Не существует "правильного" статического типа, поскольку полный тип рекурсивен:

typedef StateMethod (StateMachine::*StateMethod)();

Лучше всего использовать typedef void (StateMachine::*StateMethod)();, а затем сделать уродливый state = (StateMethod)(this->*state)();

PS: boost::function требует явного возвращаемого типа, по крайней мере, из моего чтения документы: boost::function0<ReturnType>

Да, это подход "взломать тип-безопасность", как я уже упоминал в комментариях к вопросу. На самом деле это очень плохо. Я действительно хочу, чтобы есть способ решить эту проблему чисто. Может быть, C++ 0x предоставит способ?

Chris Jester-Young 02.10.2008 09:51

Нет, на самом деле это невозможно с тщательно оцениваемой системой типов, а не только C++. Вам понадобится система типов с ленивой оценкой.

Simon Buchan 02.10.2008 09:58
Ответ принят как подходящий

GotW # 57 говорит использовать прокси-класс с неявным преобразованием именно для этой цели.

struct StateMethod;
typedef StateMethod (StateMachine:: *FuncPtr)(); 
struct StateMethod
{
  StateMethod( FuncPtr pp ) : p( pp ) { }
  operator FuncPtr() { return p; }
  FuncPtr p;
};

class StateMachine {
  StateMethod stateA();
  StateMethod stateB();
};

int main()
{
  StateMachine *fsm = new StateMachine();
  FuncPtr a = fsm->stateA();  // natural usage syntax
  return 0;
}    

StateMethod StateMachine::stateA
{
  return stateA; // natural return syntax
}

StateMethod StateMachine::stateB
{
  return stateB;
}

This solution has three main strengths:

  1. It solves the problem as required. Better still, it's type-safe and portable.

  2. Its machinery is transparent: You get natural syntax for the caller/user, and natural syntax for the function's own "return stateA;" statement.

  3. It probably has zero overhead: On modern compilers, the proxy class, with its storage and functions, should inline and optimize away to nothing.

Невозможно преобразовать указатели функций-членов в обычные указатели на функции, но в остальном это круто. Должен отметить, что вы все еще просто засахариваете гипс :).

Simon Buchan 02.10.2008 10:00

Я не занимался разработкой на C++ 5 лет и с радостью забыл об указателях на функции-члены. Да, я согласен, что это просто сахар для актеров в вашем ответе :)

Jacob Krall 02.10.2008 10:03

Если вы измените typedef, все должно быть в порядке, правда? typedef StateMethod (StateMachine :: * FuncPtr) ();

1800 INFORMATION 02.10.2008 10:04

Ах, это тот синтаксис, к которому я стремился. Спасибо!

Jacob Krall 02.10.2008 10:09

Используя только typedef:

class StateMachine {  

 public:  

  class StateMethod;     
  typedef StateMethod (StateMachine::*statemethod)();   

  class StateMethod {  

    statemethod   method; 
    StateMachine& obj; 

   public:  

    StateMethod(statemethod method_, StateMachine *obj_)  
      : method(method_), obj(*obj_) {} 

    StateMethod operator()() { return (obj.*(method))(); }  
  };  

  StateMethod stateA()  { return StateMethod(&StateMachine::stateA, this); }  

  StateMethod stateB()  { return StateMethod(&StateMachine::stateB, this); }  

};    

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

Так дано:

class StateMachine { 
    bool stateA(int someArg); 
};

Какой синтаксис у typedef stateA? Понятия не имею ... так что давайте попробуем присвоить ему что-то несвязанное и посмотрим, что скажет компилятор:

char c = StateMachine::stateA

Компилятор говорит:

error: a value of type "bool (StateMachine::*)(int)" cannot be used to initialize 
       an entity of type "char" 

Вот он: "bool (StateMachine :: *) (int)" - это наш typedef.

Другие вопросы по теме