Почему следующая шаблонная функция-член класса не компилируется? - PullRequest
3 голосов
/ 06 февраля 2020

Следующий код компилируется, хотя nonexisting_func() не существует. Код компилируется, потому что это функция-член шаблонного класса, но сама функция не компилируется, потому что она не используется в программе, правильно? Таким образом, у вас могут быть какие-либо синтаксические ошибки внутри heapify_down, и весь код все еще должен компилироваться?

#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;
}

Если мое понимание выше верно, то почему следующий код не компилируется?

#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;
}

Компиляция этого кода вызывает ошибку error: use of undeclared identifier 'a'. Почему он пытается скомпилировать функцию heapify_down() сейчас?

Ответы [ 2 ]

4 голосов
/ 06 февраля 2020

Код шаблона в основном состоит из двух проходов. Первый проход просто смотрит на код и проверяет, что он синтаксически корректен и что любой независимый код корректен. Под независимым кодом я подразумеваю код, который не зависит от параметров шаблона.

После этого происходит второй проход после фактического создания шаблона. На этом этапе больше нет зависимого кода, так как все параметры шаблона известны, и компилятор может проверить код, как это было бы для любого не шаблонного кода.

In

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

вызов nonexisting_func зависит от vec из-за ADL , а vec зависит от T, поэтому его компиляция отложена. Это синтаксически правильно, поэтому дальнейшая проверка не будет выполнена, пока он не будет создан. Если вы изменили main на

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

, так что экземпляр heapify_down фактически будет создан, вы получите ошибку компилятора, такую ​​как

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.

Вы также получите ошибку, используя

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

Потому что теперь у нас больше нет неквалифицированного имени, поэтому ADL игнорируется, означая, что ::nonexisting_func больше не является зависимым именем.

С

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

a hasn не зависит от T, поэтому компилятор пытается его найти. Он не может найти его, поэтому вы получаете ошибку. Если вместо этого вы сделали

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

, то снова вы не получите ошибку, пока не создадите экземпляр функции, поскольку a теперь зависит от this, а this зависит от T.

3 голосов
/ 06 февраля 2020

Ключевым моментом здесь является то, что nonexisting_func(vec); будет означать что-то другое в зависимости от того, что T (так как ve c является vector<T>).

Так что в этом случае, компилятор не может попытаться разрешить вызов nonexisting_func() немедленно, так как он выполняет функцию лексизма, и может сделать это только тогда, когда наступит время для создания экземпляра шаблона (чего вы никогда не делаете).

В случае a, поскольку этот идентификатор ни от чего не зависит, компилятор должен выполнить поиск немедленно. Я должен сказать, потому что MSV C, в частности, имеет тенденцию задерживать поиск до момента его создания, даже если это не должно быть на бумаге.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...