5

Я понимаю, что вы не можете частично специализировать шаблон функции, я также понимаю типичную перегрузку функции.Пример правила специализации/перегрузки

Где мне нужна помощь в поиске различий между нижеуказанными функциями foo(). Я ожидаю, что некоторые из них отличаются от синтаксиса точно так же?

Может ли кто-нибудь более осведомленному объяснить каждую функцию, что именно происходит с ней, это специализированная специализация или перегрузка шаблона, и как компилятор C++ определяет, что нужно вызывать?

//(1) 
template<typename T> 
void foo(T t) 
{ 
    cout << "template<T> foo(T) " << endl; 
} 

//(2) 
template<> 
void foo<int*>(int* l) 
{ 
    cout << "template<> foo<int*>(int*) " << endl; 
} 

//(3) 
template<typename T> 
void foo(T* l) 
{ 
    cout << "template<T> foo(T*) " << endl; 
} 

//(4) 
void foo(int* l) 
{ 
    cout << "normal overload foo(int*) " << endl; 
} 

int main() 
{ 
    int x = 0; 
    foo(x); 
    foo(&x); 
    return 0; 
} 

Программа выхода:

template<T> foo(T) 
normal overload foo(int*) 
+0

@ Rakete1111 вы правы. Ред. – Jordan

ответ

1

Давайте рассмотрим первый звонок, foo(x).

int не может быть записан как указатель, не может вывести параметр, следующий

void foo(int* l); 

Невозможно преобразовать int в int* неявно, следующий

template<typename T> 
void foo(T t); 

Это похоже на хороший матч , как помните это как 2). Следующая

template<> 
void foo<int*>(int* l); 

Невозможно преобразовать int в int* неявно, следующий

template<typename T> 
void foo(T* l) 

Таким образом, единственно возможный матч 2), и поэтому template<T> foo(T) является выходом.


Второй звонок, foo(&x).

void foo(int* l); 

Функция не-шаблон, который соответствует отлично тип x. Вспомним этот.

template<typename T> 
void foo(T t); 

Хорошее совпадение! Но предыдущая еще лучше, ряд

template<> 
void foo<int*>(int* l); 

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

template<typename T> 
void foo(T* l) 

Лучше, чем специализация, шаблон без, но не бьет не шаблонный.

Итак, в конце вызывается функция без шаблона.Не-шаблоны всегда лучше, чем шаблоны.

+0

Стоит отметить, что разрешение перегрузки выбирает только базовый шаблон, поэтому 2) не может быть выбран до разрешения перегрузки. http://www.gotw.ca/publications/mill17.htm –

+0

@VS Вы имеете в виду, что базовый шаблон перегрузки никогда не выбирается, потому что есть специализация – Rakete1111

+1

«Только после того, как будет определено, какой базовый шаблон будет выбран, и этот выбор заблокирован, будет ли компилятор оглядываться, чтобы увидеть, есть ли подходящая специализация этого шаблона, и если это поможет специализации ». Итак, я имею в виду, что специализация шаблона выглядит ПОСЛЕ перегрузки. –

5

Пояснения в комментариях:

// the 1st primary function template, overloaded function template 
template<typename T> 
void foo(T t) 

// full template specialization of the 1st function template with T = int* 
template<> 
void foo<int*>(int* l) 

// the 2nd primary function template, overloaded function template 
template<typename T> 
void foo(T* l) 

// non-template function, overloaded function 
void foo(int* l) 

int main() 
{ 
    int x = 0; 
    foo(x); // only match the 1st function template; the others take pointer as parameter 
    foo(&x); // call the non-template function, which is prior to templates in overload resolution 
    return 0; 
} 

Смотреть подробнее о overload resolution и explicit (full) template specialization.

0

Разрешение foo(x) легко определить, так как нет никаких дополнительных функций, кроме template<typename T> void foo(T t).

Таким образом, наша проблема сводится к: Почему void foo(int* l) для foo(&x) позвонить?

  1. Для вызова шаблонный метод template<> void foo<int*>(int* l) , вам нужно позвонить foo<int*>(&x)
  2. template<typename T> void foo(T* l) по телефону foo<int>(&x)
  3. template<typename T> void foo(T t) по телефону foo<int*>(&x)

Как вы можете видеть, вызывая foo(&x) не соответствует любому из вышеупомянутых трех стилей вызова с явными шаблонами.

Обратите внимание, что при отсутствии специализированной функции void foo(int* l), вызова функции foo<int*>(&x) будет решены с помощью специализированной матричной функцииtemplate<> void foo<int*>(int* l) избиения Неспециализированной шаблонных функцийtemplate<typename T> void foo(T t)

+0

В отсутствие специализированной функции 'void foo (int * l)', 'template void foo (T * l)' будет вызываться для вызова 'foo (& x)'. –

0

при попытке определить, какие функции вызывается при перегрузке, правило: всегда находить функцию, требующую наименьшей оптимизации.

Когда foo() вызывается с помощью int, единственная функция, которую можно использовать, является первой, поскольку вы не можете преобразовать int в int *.

при использовании его с int *:
функция 4 может использоваться без какой-либо оптимизации.
Для выполнения функции 3 необходимо изменить T-> int.
Функция 1 должна изменить T на тип указателя и определить, что T указывает на int.
Функция 2 является специализацией функции 1

поэтому функция 4 может быть использована немедленно, функция 2 должна обновить тип шаблона, а функции 1,2 должны обновить тип шаблона и тип объекта.
, поэтому их вызывают в следующем порядке: 4 затем 3, затем 2 затем 1

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