2013-10-25 3 views
1

В this article они говорят (в) явную специализацию (b). Мое сомнение в том, почему мы не можем сказать, что это явная специализация (а)? потому что мы можем специализировать шаблон для любого конкретного типа. поэтому, специализируясь на int *, почему они говорят (c) явную специализацию (b).функция шаблон явная специализация

template<class T> // (a) a base template 
void f(T); 

template<class T> // (b) a second base template, overloads (a) 
void f(T*);  //  (function templates can't be partially 
       //  specialized; they overload instead) 

template<>   // (c) explicit specialization of (b) 
void f<>(int*); 

Любые комментарии будут полезны для понимания вещей.

+0

http://www.gotw.ca/publications/mill17.htm –

+0

http://stackoverflow.com/questions/14786008/ – Mehrdad

ответ

3

Если (b) не существует, то (c) действительно будет действительной специализацией (a). Фактически, просто изменяя порядок исходных строк, чтобы (c) появлялся до того, как компилятор увидел (b), он станет специализацией (a)!

Рассмотрим следующий код:

int main() 
{ 
    int a; 
    f(&a); 
    return 0; 
} 

Теперь поставьте себя на место компилятора. Вам нужно найти подходящую функцию f с аргументом int*. Чем ты занимаешься?

  • Во-первых, вы пытаетесь все функции не-шаблон под названием f, что вы знаете о, и посмотреть, если есть какие-либо которые соответствуют типам аргументов (в данном случае, int*).
  • Если вы не можете получить идеальное совпадение, вы можете посмотреть все базовые шаблоны , о которых вы знаете. В этом случае есть два: f<T> и f<T*>. Обратите внимание, что в отличие от классов шаблоны функций не могут быть частично специализированными, поскольку в отношении компилятора это полностью отдельные перегрузки.
  • Очевидно, что базовый шаблон f<T*> лучше подходит, поэтому вы создаете его с помощью T=int. Теперь, если вы уже видели специализацию для f<int*>, тогда вы используете это, и в противном случае вы создадите функцию.

Теперь вот забавная вещь. Если мы изменим порядок исходного кода, чтобы

template<class T> void f(T); // (i) 

template<> void f<>(int*); // (ii) 

template<class T> void f(T*); // (iii) 

то компилятор теперь видит (II) в качестве специализации (I) - потому что она обрабатывает вещи в порядке, и в точке она достигает (б) он не знает, что (iii) существует еще! Но поскольку он соответствует только базовым шаблонам, он решает, что (iii) является лучшим совпадением, чем (i) - и теперь (iii) не имеет специализации, поэтому вы получаете экземпляр по умолчанию.

Все это довольно запутанно, и время от времени можно даже опробовать даже самых опытных программистов на С ++. Итак, основным правилом является следующее: не специализируются на функциональных шаблонах, но вместо этого используют нормальную функцию перегрузки. Обычный старый, не шаблонный

void f(int*); 

был бы согласован перед чем-либо еще и избегает всего этого беспорядка.


EDIT: Н.М. запросил ссылки на стандарт в комментариях. Боюсь, у меня есть только версия C++ 03, но здесь идет речь:

Пункт 4.7.3.3: «Объявление шаблона функции или шаблона класса, явно специализированного, должно быть в области видимости в точке декларации явной специализации»..

Вот почему в приведенном выше примере (ii) нельзя рассматривать как явную специализацию (iii), поскольку (iii) еще не охвачена.

Раздел 4.8.3: «Когда записывается вызов этого имени [функции] ... вывод аргумента шаблона (14.8.2) и проверка любых явных аргументов шаблона (14.3) выполняется для каждого шаблона функции, чтобы найти значения аргументов шаблона (если они есть), которые можно использовать с этим шаблоном функции, чтобы создать экземпляр специализированной функции, которая может быть вызвана с помощью аргументов вызова. "

Другими словами, (как я его читал, во всяком случае) он всегда смотрит на каждый базовый шаблон независимо от того, что - предоставление явной специализации не имеет значения.

Этот же параграф продолжается: «Для каждого шаблона функции, если вывод аргументов и проверка завершаются успешно, аргументы-шаблоны (выводимые и/или явные) используются для создания экземпляра специализированной специализированной функции, которая добавляется к кандидатские функции, установленные для использования при разрешении перегрузки. «

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

Наконец, и, самое главное, в этом случае раздел 13.3.3 посвящен выбору «наилучшей жизнеспособной функции» в наборе перегрузки. Две вещи являются релевантными:

  • F1 лучше, чем F2, если: «F1 и F2 функции шаблона специализаций, а шаблон функции для F1 является более специализированным, чем шаблон для F2 в соответствии с частичными правилами порядка описанных в 14.5.5.2 ". Поэтому версия f<T*> получает взял впереди версии f<T> при попытке соответствовать f(int*) - потому что это «более специализированные» шаблон

  • F1 лучше, чем F2, если: «F1 является функцией не-шаблон и F2 - это специальная функция шаблона «, которая послужила основой для моего совета в конце исходного ответа.

Фу!

+0

Можете ли вы показать соответствующий язык в стандарте? –

+0

См. Правки, слишком много, чтобы добавить комментарий! –

+0

Котировки не отвечают на главный вопрос: * почему (c) является специализацией (b), а не (a) *. Оба (а) и (б) находятся в сфере охвата, почему (б) выбрано? –

Смежные вопросы