Pregunta

Básicamente tengo la siguiente clase:

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

Los métodos stateA () y stateB () deben poder devolver los punteros a stateA () y stateB (). ¿Cómo mecanografiar el método de estado?

¿Fue útil?

Solución

GotW # 57 dice usar una clase proxy con una conversión implícita para esto muy propósito.

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;
}
  

Esta solución tiene tres principales   fortalezas:

     
      
  1. Resuelve el problema según sea necesario. Mejor aún, es de tipo seguro y   portátil.

  2.   
  3. Su maquinaria es transparente: se obtiene una sintaxis natural para el   llamador / usuario, y sintaxis natural para   la propia función " return stateA; "   declaración.

  4.   
  5. Probablemente no tenga sobrecarga: en los compiladores modernos, la clase proxy,   con su almacenamiento y funciones, debe   en línea y optimizar a la nada.

  6.   

Otros consejos

Usando sólo 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); }  

};    

EDITAR: njsf demostró que estoy equivocado aquí. Sin embargo, es posible que encuentre que el lanzamiento estático es más fácil de mantener, por lo que dejaré el resto aquí.

No hay un tipo estático 'correcto' ya que el tipo completo es recursivo:

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

Su mejor apuesta es usar typedef void (StateMachine :: * StateMethod) (); luego hacer el feo state = (StateMethod) (this- > * state) () ;

PS: boost :: function requiere un tipo de retorno explícito, al menos de mi lectura de docs : boost::function0<ReturnType>

Mi filosofía es no usar punteros de función miembro sin procesar. Ni siquiera sé realmente cómo hacer lo que quieres usando el puntero sin formato, la sintaxis es tan horrible. Me gusta usar boost :: function.

Esto es casi ciertamente mal:

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); }
};

Este problema es definitivamente mucho más difícil de lo que parece.

Nunca puedo recordar la horrible función C ++ declspec, así que cada vez que tengo que averiguar la sintaxis que describe una función miembro, por ejemplo, solo induzco un error de compilación intencional que generalmente muestra la sintaxis correcta para mí.

Así dado:

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

¿Cuál es la sintaxis de typedef de stateA? No tengo idea ... así que intentemos asignarle algo no relacionado y ver qué dice el compilador:

char c = StateMachine::stateA

El compilador dice:

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

Ahí está: " bool (StateMachine :: *) (int) " es nuestro typedef.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top