Шаблон специализированной функции для ссылочных типов

Почему вывод этого кода:

#include <iostream>  
template<typename T> void f(T param) 
{ 
   std::cout << "General" << std::endl ; 
} 
template<> void f(int& param) 
{ 
   std::cout << "int&" << std::endl ; 
}  

int main() 
{   
  float x ;  f (x) ;   
  int y ; f (y) ;   
  int& z = y ; f (z) ; 
}  

is

Общие
Общие
Общие

Третий вызывает удивление, потому что функция была специализирована именно для int&

Изменить: я знаю, что перегрузка может быть правильным решением. Я просто хочу изучить логику этого.


person ali_bahoo    schedule 13.01.2011    source источник
comment
Может быть, потому, что const int& предпочтительнее, чем int&?   -  person Septagram    schedule 13.01.2011
comment
@Септаграмма: const int& ?   -  person ali_bahoo    schedule 13.01.2011
comment
Я не знаю, поможет ли это, но если вы измените шаблон, чтобы принять T &, то и f(y), и f(z) вызовут версию int &.   -  person Daniel Gallagher    schedule 13.01.2011
comment
@Daniel Gallagher: Тогда у вас есть ошибка компилятора с f(2);. Также выход f(y) равен int&.   -  person ali_bahoo    schedule 13.01.2011
comment
Лучше всего использовать перегрузку void f(int& param) gotw.ca/publications/mill17.htm   -  person hansmaad    schedule 13.01.2011
comment
Вы можете переключиться на const T & и const int &, чтобы заставить работать f(2), но да, f(y), f(z) и f(2) будут вызывать версию const int &.   -  person Daniel Gallagher    schedule 13.01.2011
comment
@Johnsyweb: ideone.com/lRck6   -  person ali_bahoo    schedule 13.01.2011
comment
Ваш код не должен компилироваться. Правильная спецификация шаблона функции выглядит так: template < > void f<int&>(int& blah)...   -  person Edward Strange    schedule 13.01.2011
comment
@Ноа Робертс: это был ответ на удаленный комментарий;   -  person ali_bahoo    schedule 13.01.2011
comment
@sad_man - а? Я не имел в виду ваш комментарий.   -  person Edward Strange    schedule 13.01.2011


Ответы (3)


Типом выражения y и выражения z является int. Ссылка, появляющаяся в выражении, не сохраняет ссылочный тип. Вместо этого тип выражения будет ссылочным типом, а выражение будет lvalue.

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

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

person Johannes Schaub - litb    schedule 13.01.2011
comment
+1 (и спасибо, что заметили ошибку в моем собственном ответе, пока я это делаю) - person Matthieu M.; 13.01.2011
comment
По поводу вашего второго предложения: откуда взялось это правило? Я доверяю вам, но есть ли у вас источник, объясняющий этот момент? Спасибо. - person Oodini; 08.06.2021

Ссылка - это просто псевдоним, а не тип. Поэтому, когда вы вызываете f(z), она соответствует первой версии с T=int, что является лучшим вариантом, чем T=int&. Если вы измените T на T&, то аргументы int и int& будут вызывать вторую версию.

person Benjamin Lindley    schedule 13.01.2011
comment
Если я изменю T на T&, у меня будет ошибка компилятора, когда f(2) или f("text") - person ali_bahoo; 13.01.2011

Я знаю, что это не ответ, но, ИМХО, вы можете попробовать это с такой чертой, как подход в структуре:

template<typename T>
struct value_traits
{
    static void print(){std::cout << "General" << std::endl ;} 
};

template<>
struct value_traits<const long>
{
    static void print(){std::cout << "const long" << std::endl ;} 
};

template<>
struct value_traits<std::vector<unsigned char> >
{
    static void print(){std::cout << "std::vector<unsigned char>" << std::endl ; }
};

template<>
struct value_traits<const int>
{
       static void print(){std::cout << "const int" << std::endl ;} 
};
person baris.aydinoz    schedule 13.01.2011