Путаница вокруг явного создания экземпляра шаблона

Что ж, я думаю, что меня очень смущает явное создание экземпляра шаблона ~> _ ‹~

  1. Может ли явное объявление создания экземпляра использовать неявное определение экземпляра?
  2. Что, если в программе существуют как явные, так и неявные определения экземпляров? Смогут ли они в конечном итоге превратиться в единую?
  3. Имеет ли какой-либо эффект явное объявление создания экземпляра, если оно помещено после определения неявного создания экземпляра?

Также см. Следующий код:

#include <iostream>
#include <vector>

std::vector<int> a;  // Implicit instantiation definition.

// Explicit instantiation declaration.
extern template class std::vector<int>; 

int main() {
  std::cout << std::vector<int>().size();  // So what?
}

Это вызывает ошибку ссылки

/tmp/ccQld7ol.o: In function `_GLOBAL__sub_I_a':
main.cpp:(.text.startup+0x6e): undefined reference to `std::vector<int, std::allocator<int> >::~vector()'
collect2: error: ld returned 1 exit status

с GCC 5.2, но отлично работает с clang 3.6. Какой из них правильный по стандарту?

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


person Lingxi    schedule 01.10.2015    source источник


Ответы (2)


[temp.explicit] / p11:

Сущность, которая является предметом явного объявления экземпляра и который также используется таким образом, который в противном случае вызвал бы неявное создание экземпляра (14.7.1) в блоке перевода, должен быть предметом явного определения экземпляра где-то в программе; в противном случае программа имеет неправильный формат, и диагностика не требуется.

person T.C.    schedule 02.10.2015
comment
Означает ли это, что явное объявление экземпляра может использовать только явное определение экземпляра, и что GCC является правильным для второго использования std::vector после явного объявления экземпляра, должен пытаться только связываться с явным определением создания экземпляра, которое отсутствует в примере? Тогда как насчет вопроса 2? - person Lingxi; 02.10.2015
comment
Если приведенная выше интерпретация верна, стандарт, кажется, проводит четкое различие между неявными и явными определениями экземпляров, и ответ на вопрос 2 не очевиден. - person Lingxi; 02.10.2015

Во-первых, похоже, что вы слишком задумываетесь о явном экземпляре. В этом нет ничего особенного. Все, что он делает, это позволяет кому-то использовать шаблонную функцию или класс без видимого определения шаблона. Это делается путем создания экземпляра функции или класса с указанным шаблоном, так что это уже не шаблон, а фактическая полезная вещь. Его можно использовать, например, когда у вас есть класс шаблона, но вы хотите скрыть фактический код в файле .cpp, который вы никогда не предоставляете пользователям - вместо этого вы передаете им скомпилированный файл .o. Чтобы он работал, вы можете явно создать экземпляр своего шаблона с типами, которые, по вашему мнению, потребуются вашим пользователям для аргументов шаблона. (конечно, это редкий случай, когда набор типов известен так). Больше ничего нет.

Неявные и явные экземпляры одного и того же типа могут существовать вместе. Неявное создание экземпляра даст слабый символ, явное - «сильный». Сильные символы имеют приоритет над слабыми символами, и нет нарушения ODR. Все будет хорошо.

Что касается имеющейся у вас ошибки, вам необходимо удалить extern из вашего явного экземпляра.

person SergeyA    schedule 01.10.2015
comment
Что не так с extern, если в неявном определении экземпляра предоставляется слабый символ? - person Lingxi; 01.10.2015
comment
Я не юрист по языку, поэтому я не могу комментировать законность этого, но, очевидно, когда g ++ видит явный экземпляр шаблона и не пытается неявно (имеет смысл для меня), он ожидает найти все символы, которые ему нужны, без выполнение любых экземпляров. Поскольку это внешний вид, он ожидает, что они будут предоставлены кем-то другим. - person SergeyA; 01.10.2015