9

Tengo otra pregunta relacionada con el lenguaje bool segura:const-corrección y el bool segura idioma

typedef void (Testable::*bool_type)() const;    // const necessary? 
void this_type_does_not_support_comparisons() const {} // const necessary? 

operator bool_type() const 
{ 
    return ok_ ? &Testable::this_type_does_not_support_comparisons : 0; 
} 

¿Cómo es que la bool_type (typedef) y this_type_does_not_support_comparisons son const? Nadie se supone que realmente llame al la función de miembro a través del puntero de retorno de todos modos, ¿verdad? ¿Es necesario const aquí? ¿De lo contrario, operator bool_type (la función miembro) violaría la corrección de const?

+0

Mi apuesta es que 'const' no es necesario. Tampoco es un cuerpo para la función, ya que se supone que no debes llamar a la función de todos modos. –

+0

@Alex: Pero una función miembro sin cuerpo no tiene dirección, ¿verdad? No se compila sin un cuerpo en VC10, al menos. – fredoverflow

+0

hmm tienes razón. Acabo de revisar mi plantilla 'safe_bool' Tengo un profundo en mi proyecto actual VS2010 y tiene un cuerpo. Tiene 'const' también. –

Respuesta

5

La expresión idiomática de "bool seguro" es la respuesta técnica a la pregunta "quiero un vehículo que sea tanto deportivo como tractor, y tal vez un barco". La respuesta práctica no es la respuesta técnica & hellip;

Dicho esto, el problema que resuelve es simplemente dar un resultado que es convertible a bool pero no a mucho más (de lo contrario una instancia de la clase podría pasar como argumento real donde por ejemplo el argumento formal fue int, decir). Un puntero de datos podría ser convertible a void*. Un puntero a la función no está, al menos formalmente dentro del estándar de C++ (Posix es otra cosa, también práctica).

El uso de un puntero de función miembro protege contra la llamada accidental de la función, dado el puntero del operador de bool seguro. El const restringe un poco, pero si el destino ha puesto a alguien en el camino de cometer el mayor número de errores tontos, esa persona aún podría llamar a la función de no hacer nada. En lugar de const, creo que simplemente dejaría que tenga un argumento de tipo privado, donde otro código no puede proporcionar ese argumento, y entonces ya no tiene que ser un tipo de función tonto.

podría tener este aspecto:

#include <stdio.h> 

class Foo 
{ 
private: 
    enum PrivateArg {}; 
    typedef void (*SafeBool)(PrivateArg); 
    static void safeTrue(PrivateArg) {} 

    bool state_; 

public: 
    Foo(bool state): state_(state) {} 

    operator SafeBool() const 
    { return (state_? &safeTrue : 0); } 
}; 

int main() 
{ 
    if(Foo(true)) { printf("true\n"); } 
    if(Foo(false)) { printf("false\n"); } // No output. 

    //int const x1 = Foo(false);  // No compilado! 
    //void* const x2 = Foo(false);  // No compilado! 
} 

Por supuesto, la respuesta práctica es en cambio algo como esto:

#include <stdio.h> 

class Foo 
{ 
private: 
    bool isEmpty_; 

public: 
    Foo(bool asInitiallyEmpty) 
     : isEmpty_(asInitiallyEmpty) 
    {} 

    bool isEmpty() const { return isEmpty_; } 
}; 

int main() 
{ 
    if(Foo(true).isEmpty()) { printf("true\n"); } 
    if(Foo(false).isEmpty()) { printf("false\n"); } // No output. 

    //bool const x0 = Foo(false);  // No compilado! 
    //int const x1 = Foo(false);  // No compilado! 
    //void* const x2 = Foo(false);  // No compilado! 
} 

Resumen WRT. preguntas hechas:

  • ¿Cómo es que el bool_type (typedef) y this_type_does_not_support_comparisons son const?

Alguien no entendió exactamente lo que codificaron. O tal vez tenían la intención de restringir la capacidad de llamar, un poco. Pero entonces, una medida bastante inútil.

  • En realidad, se supone que nadie llama a la función miembro a través del puntero de retorno, ¿verdad?

Derecha.

  • ¿Es necesario const aquí?

  • Would bool_type operador (la función miembro) viola const-corrección de otro modo?

No.

Saludos & HTH.,

+0

"Creo que simplemente dejaría que tenga un argumento de tipo privado", oh, espera, me retracto de mi declaración anterior, ¡esto es brillante! – fredoverflow

+0

Escribí algo mal sobre el 'const', de alguna manera confuso en blanco y negro. Solo lo golpeo. Lo siento, el resto está bien sin embargo. –

+0

Todavía puede (estúpidamente, pero este es el objetivo del ejercicio) declarar una función gratuita con la firma 'void (Foo :: PrivateArg)' y compararla con el resultado del 'operador SafeBool'. Creo que el tipo 'SafeBool' debe ser un puntero a la función miembro después de todo. –

1

8.3.5/A cv-calificador-seq sólo será parte del tipo de función para una función no estática miembro, el tipo de función a la que se refiere un puntero a miembro, o el tipo de función de nivel superior de una función typedef declaration. El efecto de un cv-qualifier-seq en un declarador de función no es lo mismo que agregar cv-qualification sobre el tipo de función , es decir, no crea un tipo de función cv-qualified.

Si leo correctamente, puede devolver un puntero a miembro no const en un método constante. Simplemente no podrá llamarlo con un objeto no const.

Una manera de prohibir la llamada es:

private: 
    struct private_ 
    { 
     void this_type_does_not_support_comparisons() {} 
    }; 

public: 
    typedef void (private_::*bool_type)() const; 

    operator bool_type() const 
    { 
     return ok_ ? &private_::this_type_does_not_support_comparisons : 0; 
    } 

Puntero a las funciones miembro sí puede compararse a la igualdad. Debe escribir un operator== y operator!= para los tipos Testable::bool_type que desencadenan un error. Más fácil de hacer con la forma CRTP del idioma bool seguro, ya que esos operadores se convierten en plantillas y, por lo tanto, pueden tener un cuerpo erróneo.

Ejemplo:

template <typename T> 
class safe_bool_concept 
{ 
    // Implementation detail of safe bool 
protected: 
    ~safe_bool_concept() {} 

public: 
    operator safe_bool() const 
    { 
     return static_cast<const T*>(this)->is_null() ? ...; 
    } 
}; 

struct Foo : safe_bool_concept<Foo> 
{ 
    ... 

private: 
    friend class safe_bool_concept<Foo>; 
    bool is_null() const { ... } 
}; 

entonces usted puede hacer (hacer lo mismo con !=):

template <typename T> 
void operator==(const safe_bool_concept<T>& x, const safe_bool_concept<T>&) 
{ 
    x.some_private_member(); // invalid, but won't be generated 
          // unless safe_bool classes are compared 
} 

Esto significa que el idioma bool segura debe ser implementado a través de CRTP si desea prohibir las comparaciones . Sin embargo, las comparaciones a cero seguirán funcionando.

Si vas a la ruta función no miembro, usted tiene que proporcionar <, >, <= y >= también.

+0

@Alf: déjame escribir un código, para que mi intención sea más clara. –

Cuestiones relacionadas