es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

En IsClassT, ¿por qué se utiliza “int C::*”? Estoy confundido(a) sobre el tipo int.

Un ejemplo descrito en el libro C++ Templates The Complete Guide:
“`c++
template <typename T>
class IsClass {
private:
typedef char One;
typedef struct { char a[2];} Two;

<pre><code>template<typename C> static One test(int C::*);
template<typename C> static Two test(…);
</code></pre>

public:
enum {
Sí = (sizeof(IsClass<T>::test<T>(0)) == 1)
};
enum {
No = !Sí
};
};
“`

He leído un tema relacionado Donde puedo encontrar una descripción sobre el uso de “int C::“?
Ya tengo el concepto de que C:: significa un puntero a miembro, y test(0) significa test(nullptr), pero tengo algunas otras preguntas:

  1. Supongamos que el compilador no verifica si la clase C realmente tiene un miembro de tipo int. ¿Por qué el compilador no verifica esto?
  2. El tipo int en int C::* podría ser reemplazado por cualquier tipo excepto void, aunque creo que void es menos confuso. ¿Por qué se reporta este error?
    c++
    In file included from testisclass.cpp:12:
    ../inc/isclass.hpp:17:54: error: no se puede declarar un puntero a un miembro 'void'
    17 | template<typename C> static One test(void C::*);
    | ^
    ../inc/isclass.hpp: In instantiation of ‘class IsClass<A>’:
    testisclass.cpp:22:16: required from here
    ../inc/isclass.hpp:17:41: error: creando un puntero a un miembro de tipo void
    17 | template<typename C> static One test(void C::*);
    | ^~~~
    ../inc/isclass.hpp: In instantiation of ‘class IsClass<int>’:
    testisclass.cpp:28:18: required from here
    ../inc/isclass.hpp:17:41: error: creando un puntero a un miembro de tipo void
  3. = verdadero/falso es una definición completa, ¿por qué todavía se define No?
Tags:  ,

Answer

  1. Avatar for davy.ai
    1. El compilador no está verificando si la clase C tiene un miembro de tipo int porque el objetivo principal de este código es comprobar si el tipo T es una clase o no. El uso de int C:: como parámetro para la función de prueba es solo un truco para diferenciar entre clases y no clases. Si T es una clase, int C:: es un puntero a miembro válido, por lo que se selecciona la primera versión de la función de prueba. De lo contrario, si T no es una clase, int C:: es un puntero a miembro inválido, por lo que se selecciona la segunda versión de la función de prueba. Esta técnica se llama SFINAE (Substitution Failure Is Not An Error), y permite al compilador descartar sobrecargas inválidas en tiempo de compilación en lugar de generar un error en tiempo de compilación.

    2. El error se reporta porque no se permite un puntero a un miembro de tipo void en C++. Esta restricción existe porque un puntero a un miembro debe tener un tamaño conocido, pero el tamaño de un miembro de tipo void no está definido. Por lo tanto, no es posible determinar el desplazamiento de memoria de un miembro void dentro de un objeto.

    3. La definición de No es necesaria para proporcionar un conjunto completo de valores booleanos que se pueden utilizar para representar la respuesta a la pregunta “¿Es T una clase?”. Si se define Yes y no se define No, no habría forma de representar la respuesta negativa a esta pregunta. Además, definir tanto Yes como No explícitamente hace que el código sea más fácil de leer y entender, ya que evita confiar en conversiones implícitas entre valores numéricos y booleanos.

Comments are closed.