El siguiente código se compila aunque nonexisting_func() no existe. El código se compila porque es una función miembro de una clase con plantilla, pero la función en sí no se compila porque no se está utilizando en el programa, ¿correcto? Entonces, ¿podría tener algún error de sintaxis dentro de heapify_down y todo el código aún debería compilarse?

#include <iostream>
#include <vector>

template<typename T>
class heap
{
public:
   void heapify_down(std::vector<T> &vec)
   {
      nonexisting_func(vec);
   }
};

int main( ) 
{ 
   heap<int> my_heap;
   return 0;
}

Si mi entendimiento anterior es correcto, ¿por qué no se compila el siguiente código?

#include <iostream>
#include <vector>

template<typename T>
class heap
{
public:
   void heapify_down(std::vector<T> &vec)
   {
      a;
      nonexisting_func(vec);
   }
};

int main( ) 
{ 
   heap<int> my_heap;
   return 0;
}

Compilar este código me da el error error: use of undeclared identifier 'a'. ¿Por qué está tratando de compilar la función heapify_down() ahora?

3
Iamanon 6 feb. 2020 a las 22:24

2 respuestas

La mejor respuesta

El código de plantilla básicamente tiene dos pases por los que pasa. La primera pasada solo mira el código y se asegura de que sea sintácticamente correcto y de que cualquier código no dependiente sea correcto. Por código no dependiente, me refiero al código que no depende de los parámetros de la plantilla.

Después de eso hay un segundo pase que ocurre después de que la plantilla se instancia en realidad. En ese momento, no hay más código dependiente, ya que todos los parámetros de la plantilla son conocidos y el compilador puede examinar el código como lo haría para cualquier código que no sea de plantilla.

En

void heapify_down(std::vector<T> &vec)
{
    nonexisting_func(vec);
}

La llamada a nonexisting_func depende de vec debido a ADL y vec depende de T, por lo que su compilación se aplaza. Es sintácticamente correcto, por lo que no se realizarán más comprobaciones hasta que se instancia. Si cambiaste de principal a

int main( ) 
{ 
   std::vector<int> foo;
   heap<int> my_heap;
   my_heap.heapify_down(foo);
   return 0;
}

Para que heapify_down se instancia realmente, entonces obtendría un error del compilador como

main.cpp:22:7: error: use of undeclared identifier 'nonexisting_func'
      nonexisting_func(vec);
      ^
main.cpp:30:12: note: in instantiation of member function 'heap<int>::heapify_down' requested here
   my_heap.heapify_down(foo);
           ^
1 error generated.

También recibirías un error al usar

void heapify_down(std::vector<T> &vec)
{
    ::nonexisting_func(vec);
}

Debido a que ahora ya no tenemos un nombre no calificado, ADL se ignora, lo que significa que ::nonexisting_func ya no es un nombre dependiente.

Con

void heapify_down(std::vector<T> &vec)
{
   a;
   nonexisting_func(vec);
}

a no depende de T, por lo que el compilador intenta buscarlo. No puede encontrarlo, por lo que obtiene un error. Si en cambio hubieras hecho

void heapify_down(std::vector<T> &vec)
{
   this->a;
   nonexisting_func(vec);
}

De nuevo, no recibirá un error hasta que cree una instancia de la función ya que a ahora depende de this y this depende de T.

4
NathanOliver 6 feb. 2020 a las 19:57

El punto clave aquí es que nonexisting_func(vec); va a significar algo diferente dependiendo de lo que sea T (ya que vec es un vector<T>).

Entonces, en ese caso, el compilador no puede intentar resolver la llamada a nonexisting_func() de inmediato, ya que elimina la función, y solo puede hacerlo cuando llegue el momento de crear una instancia de la plantilla (lo cual nunca hace).

En el caso de a, dado que ese identificador no depende de nada, el compilador debe realizar la búsqueda de inmediato. Digo debería porque MSVC en particular tiende a retrasar la búsqueda hasta la creación de instancias, aunque no debería hacerlo en papel.

3
Frank 6 feb. 2020 a las 19:36