разница между шаблоном функции-члена класса шаблона и функцией-членом класса шаблона

КОД 1 :

template <class T>
class cat{
public:
       T a;
       void show(){
       cout << a ;
       }
};

КОД 2 :

template <class T>
class dog{
public:
       T a;
       template <class U> // making show function template
       void show(){
       cout << a ;
       }
};


поэтому cat::show() – это функция-член класса шаблона.
а dog::show() – это шаблон функции-члена класса шаблона.

Вопросы:
1) есть ли какая-либо разница между шаблоном класса cat и dog, а не когда я вызываю функцию-член show, я должен явно указать U для экземпляр класса шаблона собаки?
2) компилятор обрабатывает их одинаково. например, cat::show() не будет скомпилирован, пока я его не использую. и я думаю, то же самое для dog::show();. так есть ли что-нибудь, что мне здесь не хватает?


person AlexDan    schedule 29.06.2012    source источник


Ответы (1)


Эти две связаны только так же, как здесь связаны две свободные функции foo:

void foo() {};
template <typename T>
void foo() {}

Будучи членами класса шаблона, оба экземпляра будут создаваться по запросу для неявных экземпляров. С другой стороны, если вы явно создаете экземпляр класса шаблона, нешаблонная функция будет сгенерирована компилятором, а функция-член шаблона — нет.

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

template <typename T>
struct tmpl {
   void foo( T, T ) {}
   template <typename U>
   void bar( U, U ) {}
};
tmpl<int> t;
t.foo( 5, 1. );    // fine, will convert 1. from double to int
t.bar( 5, 1. );    // error

И все остальные различия между шаблонными и не шаблонными функциями.


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

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

person David Rodríguez - dribeas    schedule 30.06.2012
comment
но функция члена шаблона не будет. Я не думаю, что это правда. Спецификация говорит, что такие члены тоже создаются. Просто многие реализации (включая современные, такие как Clang) не будут создавать экземпляры определений шаблонов членов. Это соответствующее отклонение, потому что, если бы определение шаблона члена содержало ошибку, определение шаблона члена было бы неправильным; диагностика не требуется. Для Clang причина, по которой они не создают экземпляры определений шаблонов членов, заключается в производительности — тогда им нужно будет гораздо больше проверять типы. - person Johannes Schaub - litb; 30.06.2012
comment
@JohannesSchaub-litb: Можете ли вы указать, где в стандарте требуется создание экземпляров членов шаблона класса шаблона? В этом нет никакого смысла. Для какого аргумента шаблона должна быть создана функция-член шаблона? template <typename T> struct A { template <typename U> void f( U ) {} }; template class A<int>; для каких типов следует создавать экземпляры A<int>::f? A<int>::f<int>, A<int>::f<vector<map<pair<int,int>,double>>? - person David Rodríguez - dribeas; 01.07.2012
comment
вы предоставили T = int, поэтому созданный экземпляр A<int> получит определение шаблона функции, в котором все ссылки на T заменены на int. Как и для любого другого члена. Спецификация 14.7.2p8 довольно ясно об этом говорит. Например, это плохо сформировано; диагностика не требуется: template<typename T> struct A { template<typename U> void f(U) { T t; t.foo(); } }; template struct A<int>;. - person Johannes Schaub - litb; 01.07.2012
comment
@JohannesSchaub-litb: Я понимаю, что вы говорите, я не понимаю, как это относится к моему ответу. Возможно, я неправильно сформулировал это, намерение (позвольте мне попробовать еще раз) состоит в том, чтобы сказать, что компилятор не будет генерировать код для шаблонной функции-члена. Это (почти) ортогонально тому, правильно или неправильно сформирована функция-член шаблона: код не будет сгенерирован. Среди других причин (опять же, независимо от того, правильно или неправильно сформирован результат), потому что компилятор не может сгенерировать код для всех потенциальных экземпляров функции-члена шаблона. - person David Rodríguez - dribeas; 01.07.2012
comment
... для всех других (не шаблонных) членов компилятор знает, каковы аргументы шаблона: аргументы шаблона класса, но для вложенных шаблонов (будь то функции или вложенные типы) нет таких знаний, программа может использовать эти шаблоны с любой комбинацией аргументов или вообще без них, поэтому компилятор не может угадать используемые типы или создать экземпляры для всех (поскольку существует бесконечное количество типов, а нам нравится наша компиляторы завершат работу за конечное время) - person David Rodríguez - dribeas; 01.07.2012
comment
Хорошо, это могло быть намерением, но вы ничего не упоминаете о создании кода, а о создании функций и о том, что не генерируются шаблоны функций-членов. Вы говорите, что функция, не являющаяся шаблоном, будет сгенерирована компилятором, а функция-член шаблона — нет.. - person Johannes Schaub - litb; 02.07.2012
comment
Также вы говорите, что поэтому компилятор не может угадать используемые типы или создать экземпляр для всех -> Нет. Вы предоставили T. Компилятор знает, что это за аргументы: аргументы шаблона класса. Нет никакой разницы между шаблоном элемента и элементами, не являющимися шаблонами, несмотря на тот факт, что создание экземпляра шаблона элемента дает другой шаблон. - person Johannes Schaub - litb; 02.07.2012
comment
Возможно, вы лучше поймете это, если объяснение не будет сжато в одном из этих полей для комментариев: thread.gmane.org/gmane.comp.compilers.clang.devel/22398/ - person Johannes Schaub - litb; 02.07.2012