2010-07-22 19 views
13

tengo estructura para almacenar la función de devolución de llamada de esta manera:Usando la plantilla para el valor de retorno. cómo manejar el retorno nulo?

template<class T> 
struct CommandGlobal : CommandBase 
{ 
    typedef boost::function<T()> Command; 
    Command comm; 

    virtual T Execute() const 
    { 
     if(comm) 
      return comm(); 
     return NULL; 
    } 
}; 

parece que debería funcionar bien, excepto cuando T es nula debido a que la función Ejecutar quiere devolver un valor ..

¿Cuál es la mejor solución a este problema?

Gracias!

+2

¿Se supone que es 'if (comm)'? – GManNickG

+0

De hecho. Solucionado ahora –

Respuesta

11

Esta respuesta se basa en this fun-fact: en una función que devuelve void, puede devolver cualquier expresión cuyo tipo sea nulo.

Así que la solución es sencilla:

virtual T Execute() const 
{ 
    if (comm) // boolean logic change, typo in OP? 
     return comm(); 
    else 
     return static_cast<T>(NULL); 
} 

Cuando T = void, la última instrucción de retorno es equivalente a return;.


Sin embargo, siento que este es un mal diseño. ¿Es NULL significativo para cadaT? No lo creo. Me gustaría lanzar una excepción:

virtual T Execute() const 
{ 
    if (comm) 
     return comm(); 
    else 
     throw std::runtime_error("No function!") 
} 

Sin embargo, esto se hace automatically by Boost, por lo que su código se convierte en la más limpia:

virtual T Execute() const 
{ 
    return comm(); 
} 

A continuación, puede añadir funcionalidad adicional, como por ejemplo:

bool empty(void) const 
{ 
    return !comm; // or return comm.empty() if you're the explicit type 
} 

Para que el usuario pueda verificar si se puede llamar antes de llamarlo. Por supuesto, en este punto, a menos que su clase tenga funcionalidades adicionales que haya omitido por el bien de la pregunta, no veo ninguna razón para no usar simplemente boost::function en primer lugar.

+2

¿ese tipo de yeso estilo C estoy viendo allí? – akira

+0

@akira: Ido. :) Solo un temporal antes de que lo retocara un poco. – GManNickG

4

Si es sólo la declaración return, esto debe hacer el truco:

virtual T Execute() const 
{ 
    if(comm) 
     return comm(); 
    return T(); 
} 

Si hay más a él, se especializan la plantilla para void.

+1

que asume que 'T' es predeterminado construible. –

+1

@Georg: Eso es verdad. Sin embargo, algunas suposiciones que tiene que hacer y la que crea un objeto predeterminado cuando no tiene una parecen menos dañinas que la suposición del código original de que 'T' se puede construir a partir de' NULL' (que falla mal si 'T' es a 'std :: string'). Si todo lo demás falla, puede crear una especialización que cree el objeto de alguna manera diferente o poner el código creando el valor de retorno predeterminado en una política. – sbi

+1

No quise decir que no es una opción, simplemente pensé que no era obvio para todos y sería mejor señalarlo :) –

Cuestiones relacionadas