[C con Clase] Un error con (¿...?) en GCC y no en Visual Studio (Parte III)

Gilberto Cuba Ricardo gilbert en ucp.ho.rimed.cu
Lun Jul 12 05:34:33 CEST 2010


Hola nuevamente Davidson,

Steven Davidson escribió:

> Hola Gilberto,

> De todas maneras, GCC no te marca ningún problema ni error en esta
> parte. Lo que sí hace GCC es - digamos - marcar la trayectoria de las 
> definiciones e invocaciones en el código fuente, para explicar donde 
> yace el error.

Sí, esto ayuda mucho y MSVC lo hace también.

>>> Ten presente que los punteros a los miembros de una clase no siguen
>>> las reglas de herencia, sino de ámbito. Por lo tanto, el puntero a
>>> una función miembro de 'MyFirstClass' no es "transferible" a un
>>> puntero de otra clase.
>> 
>> Aquí me perdí con esto y por eso la pregunta anterior.

> Con lo de "transferible", me refería a heredable. Esto lo menciono por
> si acaso pensabas que al indicar 'MyHeritClass' para conseguir un 
> puntero a un miembro suyo implicaba que también podías conseguir un 
> puntero a un miembro de una clase pariente, como 'MyFirstClass'.

> Los punteros a miembro no son heredables. Por ejemplo,

He aquí un detalle que comprendí ahora y que no sabía, pero que
tampoco me había cuestionado, es por eso mi ignorancia del caso. Esto
es lo que influyó para mí en dónde está el error. Gracias.

En esos momentos, cuando uno tiene un código así tan grande y
complejo, y se topa con errores como estos, que no son semánticos,
sino sintácticos y que la complejidad de las estructuras te hacen
perder el hilo de la lógica de la programación, y que no es posible
llevar a cabo el debugueo del código porque como dije es un error
sintáctico, cuál es la lógica o pasos a seguir para poder determinar
el problema del código? Aclaro, esta pregunta no es solamente para
Steven, sino para toda aquella persona que desee compartir sus
experiencias en la 'caza' de errores.

Por ejemplo, para empezar la respuesta de esta pregunta, yo lo que
hago es: hacer en parte lo que he hecho con este, aunque no haya
triunfado en resolver, es decir, abstraer el problema, aislarlo del
programa principal, hacia otro programa donde se manifieste de igual
forma; eliminar todo lo superfluo y que no relacione a los elementos
que intervienen en el problema, comentar en la medida que lo requiera,
las ideas que pueden generarme confusión; y por último, ir comentando,
de una manera razonable, porciones del código, de forma tal que el
problema se abtraiga lo más posible y pueda emerger de él una
generalización que me permita sacar conclusiones. Otra idea?

> void (MyFirstClass::*pfn)() = &MyHeritClass::method_01;  // ERROR

> 'pfn' es un puntero a una función miembro de 'MyFirstClass', pero lo 
> hacemos "apuntar" a la función miembro de la clase 'MyHeritClass'. Esto
> es un error; es irrelevante que 'MyHeritClass' deriva de 'MyFirstClass'.


>> Aquí igual me pierdo porque esto es lo que está escrito en el mensaje
>> anterior que he dicho que aplico como cambio en al segunda
>> especialización parcial de "definition", y que me sigue devolviendo
>> error en [3]; sólo que creo que no comenté sobre este que es:
>> 
>> |error: no matching function for call to `definition<MyFirstClass, MyHeritClass>::def_method(const char[8], void (MyFirstClass::*)())'|
>> 

> Efectivamente, el error verdadero es éste. Lo que te intentaba explicar
> es que estás invocando 'def_method()' con parámetros de la plantilla 
> diferentes a su definición. Tienes estas definiciones:

> template< class T >
> class vmt_definition : public IClassTypeInfo
> {
> public:
>    template< typename RT >
>    void def_method( const std::string& name, RT (T::* fn) () )
>    {
>    }
>    /* ... */
> };

> y luego tienes,

> template< typename T >
> struct definition< MyFirstClass, T > : public vmt_definition< T >
> {
>    definition()
>    {
>      def_method( "method1", &MyFirstClass::method01 );  // [3]
>    }
> };

> Esto último se reescribe así:
> vmt_definition<T>::def_method( std::string("method1"), 
> &MyFirstClass::method01 );

> Esto significa que el compilador intentará generar la siguiente función
> miembro donde T=MyHeritClass:

> void vmt_definition<MyHeritClass>::def_method( const std::string &, void
> (MyHeritClass::*fn) () )
> {
> }

> Sin embargo, esto no es correcto, porque invocas 'def_method()' pasando
> el miembro de la clase 'MyFirstClass', cuando su parámetro T=MyHeritClass.

> He aquí el error. El compilador no encuentra una definición de la 
> función-plantilla 'def_method()' que involucre 'MyFirstClass'. Esto es
> porque en 'definition<MyFirstClass,T>', al final usamos 
> 'definition<MyFirstClass,MyHeritClass>'.

> Nos gustaría que se generara la siguiente definción de la 
> función-plantilla 'def_method()':

> void vmt_definition<MyFirstClass>::def_method( const std::string &, void
> (MyFirstClass::*fn) () )
> {
> }

> Pero esto no ocurre en el código fuente, porque usamos 
> 'vmt_definition<MyHeritClass>'.

Más claro, ni el agua. Me queda 'claro' el asunto.

> Creo que deberías plantearte otra forma para hacer lo que quieres o
> quizás especializar las plantillas de 'definition' para los casos que 
> realmente quieres. La otra solución es la de modificar 'def_method()' 
> para que acepte otros parámetros propios para que sean diferentes al 
> parámetro de 'vmt_definition'. Por ejemplo,

> template< class T >
> class vmt_definition : public IClassTypeInfo
> {
> public:
>    template< typename RT, typename M >
>    void def_method( const std::string& name, RT (M::* fn) () )
>    {
>    }
>    /* ... */
> };

> Con esto, separamos los propios tipos ('RT' y 'M') de 'def_method()' del
> tipo ('T') de 'vmt_definition'.

> Nuevamente, no sé si esto es lo que quieres, pero vas a tener que 
> rediseñar algo.

Evidentemente está planteado para una reelaboración de la idea
completa, pero por ahora me resuelve la solución que me ha dado, que
no me la esperaba porque sólo pensé que me iba a iluminar el camino
de dónde estaba el problema, pero que me viene al dedo y, aunque es
un poco engorrosa por los cambios que tengo que llevar a cabo, me
parece segura y funcional. Nada, que es una alternativa muy buena.

Nuevamente gracias a usted y a los que pensaron y no escribieron, pero
por lo menos se hace el intento y uno logra motivar en la solución a
los problemas de programación que hacen los demás.

> Espero ir aclarando poco a poco las cosas.

> Steven

Hasta la próxima,

-- 
Salu2,
 Gilbert





Más información sobre la lista de distribución Cconclase