Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > Расскажите про template


Автор: Wowa 17.2.2005, 13:33
Расскажите, пожалуйста, про template

Что это, для чего, и краткий пример использования.

Автор: maxim1000 17.2.2005, 14:31
пример:
дали переменную, сказали посчитать в ней количество бит, равных 1
спрашиваем, для каких типов реализовать?
ответ: char,int,void*,double

можно, конечно, написать все 4 функции и не мучаться
Код

//пример для char
int CalcOnes(char x)
{
 int result=0;
 while(x)
 {
   if(x&1)
     result++;
   x>>=1;
 }
 return result;
}

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

template<class T>
int CalcOnes(T x)
{
 int result=0;
 int counter;
 char *CharPtr=(char*)&x;

 for(counter=0;counter<sizeof(T);counter++)
 {
   while(x)
   {
     if(x&1)
       result++;
     x>>=1;
   }
   CharPtr++;
 }
 return result;
}

это - просто пишется в исходном или заголовочном файле (http://forum.vingrad.ru/index.php?showtopic=41184&hl=шаблон)
когда компилятор видит попытку использования одной из таких функций (это все - абсолютно разные функции), он добавляет ее реализацию, соответственно шаблону с нужным типом вместо T:
Код

cout<<CalcOnes("qqq")<<"\n";//выведет количество 1 в битовом представлении указателя на строку :)

smile
а как сделать ссылку на конкретное сообщение?

Автор: pablo 17.2.2005, 14:32
template - это ключевое слово С++, означающее использование шаблона.

После слова template в <типы или типовые параметры>, шаблонами могут быть не только функции, но и классы.
Как правило используется там, где надо написать алгоритм который будет работать одинакого с разными типами данных.

Вот пример использования:
// List.h: interface for the List class.
//
//////////////////////////////////////////////////////////////////////

#if !defined(AFX_LIST_H__BC404E61_5B68_4FA2_82B5_99EB5C8DBFE5__INCLUDED_)
#define AFX_LIST_H__BC404E61_5B68_4FA2_82B5_99EB5C8DBFE5__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#include <iostream>

using std::cout;

#include <new>
#include "ListNode.h" // ListNode class definition

template< typename NODETYPE >
class List
{

public:
List(); // constructor
~List(); // destructor
void insertAtFront( const NODETYPE & );
void insertAtBack( const NODETYPE & );
bool removeFromFront( NODETYPE & );
bool removeFromBack( NODETYPE & );
bool isEmpty() const;
void print() const;
List< NODETYPE > & operator = (const List< NODETYPE > &);
int operator < (const List< NODETYPE > &);
int numberOfElements() const;
private:
int length;
ListNode< NODETYPE > *firstPtr; // pointer to first node

// utility function to allocate new node
ListNode< NODETYPE > *getNewNode( const NODETYPE & );
}; // end class List

// default constructor
template< typename NODETYPE >
List< NODETYPE >::List(): firstPtr( 0 ), length(0)
{
// empty body

} // end List constructor

// destructor
template< typename NODETYPE >
List< NODETYPE >::~List()
{
if ( !isEmpty() )
{ // List is not empty

ListNode< NODETYPE > *currentPtr = firstPtr;
ListNode< NODETYPE > *tempPtr;

while ( currentPtr != 0 )
{ // delete remaining nodes
tempPtr = currentPtr;
currentPtr = currentPtr->nextPtr;
delete tempPtr;

} // end while

} // end if


} // end List destructor

// insert node at front of list
template< typename NODETYPE >
void List< NODETYPE >::insertAtFront( const NODETYPE &value )
{
ListNode< NODETYPE > *newPtr = getNewNode( value );

if ( isEmpty() ) // List is empty
{
firstPtr = newPtr;
length++;
}
else
{ // List is not empty
newPtr->nextPtr = firstPtr;
firstPtr = newPtr;
length++;
} // end else

} // end function insertAtFront

// insert node at back of list
template< typename NODETYPE >
void List< NODETYPE >::insertAtBack( const NODETYPE &value )
{
ListNode< NODETYPE > *newPtr = getNewNode( value );

if ( isEmpty() ) // List is empty
{
firstPtr = newPtr;
length++;
}
else
{ // List is not empty
while(firstPtr)
{
firstPtr = firstPtr->nextPtr;
}

firstPtr->nextPtr = newPtr;
firstPtr = newPtr;
length++;

} // end else

} // end function insertAtBack

// delete node from front of list
template< typename NODETYPE >
bool List< NODETYPE >::removeFromFront( NODETYPE &value )
{
if ( isEmpty() ) // List is empty
return false; // delete unsuccessful

else
{
ListNode< NODETYPE > *tempPtr = firstPtr;

if ( firstPtr == lastPtr )
firstPtr = lastPtr = 0;
else
firstPtr = firstPtr->nextPtr;

value = tempPtr->data; // data being removed
delete tempPtr;
length--;
return true; // delete successful

} // end else

} // end function removeFromFront

// delete node from back of list
template< typename NODETYPE >
bool List< NODETYPE >::removeFromBack( NODETYPE &value )
{
if ( isEmpty() )
return false; // delete unsuccessful

else
{
ListNode< NODETYPE > *tempPtr;

if ( firstPtr->nextPtr )
firstPtr = 0;
else
{
ListNode< NODETYPE > *currentPtr = firstPtr;
while(firstPtr->nextPtr)
{
firstPtr = firstPtr->nextPtr;
}

// locate second-to-last element
while ( currentPtr->nextPtr != lastPtr )
currentPtr = currentPtr->nextPtr;

lastPtr = currentPtr;
currentPtr->nextPtr = 0;

} // end else

value = tempPtr->data;
delete tempPtr;
length--;
return true; // delete successful

} // end else

} // end function removeFromBack

// is List empty?
template< typename NODETYPE >
bool List< NODETYPE >::isEmpty() const
{
return firstPtr == 0;

} // end function isEmpty

// return pointer to newly allocated node
template< typename NODETYPE >
ListNode< NODETYPE > *List< NODETYPE >::getNewNode(const NODETYPE &value )
{
return new ListNode< NODETYPE >( value );

} // end function getNewNode

// display contents of List
template< typename NODETYPE >
void List< NODETYPE >::print() const
{
if ( isEmpty() )
{
cout << "The list is empty\n\n";
return;

} // end if

ListNode< NODETYPE > *currentPtr = firstPtr;

cout << "The list is: ";

while ( currentPtr != 0 ) {
cout << currentPtr->data << ' ';
currentPtr = currentPtr->nextPtr;

} // end while

cout << "\n\n";

} // end function print
template< typename NODETYPE >
int List< NODETYPE >::numberOfElements() const
{
return length + 1;
}
template < typename NODETYPE>
List< NODETYPE> & List< NODETYPE>:: operator = (const List< NODETYPE> &a)
{
while(!this ->isEmpty())
{
int value;
this ->removeFromBack(value);
}

ListNode< NODETYPE > *currentPtr = a.firstPtr;

while(currentPtr != 0)
{
this -> insertAtBack(currentPtr->data);
currentPtr = currentPtr->nextPtr;
}
return *this;
}

template < typename NODETYPE>
int List< NODETYPE>:: operator < (const List< NODETYPE > &a)
{
if(length < a.length)
return 1;
return 0;
}

#endif // !defined(AFX_LIST_H__BC404E61_5B68_4FA2_82B5_99EB5C8DBFE5__INCLUDED_)


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

Автор: Sardar 17.2.2005, 15:14
Учти что шаблоны в С++ создают перегруженные для каждого типа функции, твой результирующий бинарник раздувается.

По другому это работает в Java5 и C#, там все шаблоны приводятся к общему типу Object. Компилятор следит какие типы ты кладёшь в шаблон(ую функцию, класс и т.п.). В момент использования компилятор сам добавляет привидение типа к Object и обратно. Таким образом мы реально имеем всего одну функцию(метод) работающий со многими типами обьектов.

Проблема: примитивы должны обращатся в обьекты оболочки(boxing), это убивает производительность. Вывод: а на кой хранить примитивы в контейнерах, мы ведь ООП используем smile

Автор: Wowa 17.2.2005, 15:30
Цитата(pablo @ 17.2.2005, 12:32)
говоря проще, то шаблоны исбвляют программиста, от перегузки функций для разных типов и написания классов для близких типов


и все? для чего они еще могут быть полезны?

Автор: chipset 18.2.2005, 06:38
Цитата(Admin @ 17.2.2005, 04:30)
и все? для чего они еще могут быть полезны?

Вроде бы ни для чего.
А что мало? smile
Прикинь, надо былоб создавать для каждого класса класс...
Вообще то, желательно заглядывать в таких вопросах в Страуструпа или стандарт, там точнее всего написано.
pablo, используй плз. теги [code=cpp][/code]. Читать такую кашу глаза устают...

Автор: Borisff2003 18.2.2005, 08:19
Цитата

и все? для чего они еще могут быть полезны


Ну например вся STL построенна на шаблонах

Еще можешь почитать
Andrei Alexandrescu (Андрей Александреску)
Modern C++ Design (Современное проектирование на C++)
http://anatolix.naumen.ru/Books/CPlusPlus?v=fvi

Автор: Hroft 25.2.2005, 11:45
Вот это точно. Великая книга.
Моя любимая идея оттуда - разбиение классов на стратегии: множественное наследование от параметров шаблона. Потрясающая гибкость. И еще - возможность определять, является ли тип указателем (да и много чем еще). Списки типов. В общем - Loki.

Автор: De Gray 25.2.2005, 17:16
Цитата(Admin @ 17.2.2005, 15:30)
и все? для чего они еще могут быть полезны?

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

Автор: maxim1000 25.2.2005, 17:27
Цитата
Осталось только добавить, что с шаблонами каждый вызов функции превращается в довольно изощренное и долгое действо, что, есстессно, убивает производительность

шаблоны не влияют на процесс вызова функции: они пропадают сразу после компиляции

Автор: bel_nikita 25.2.2005, 19:37
chipset
Цитата
Вообще то, желательно заглядывать в таких вопросах в Страуструпа или стандарт, там точнее всего написано
Hroft
Цитата
еще - возможность определять, является ли тип указателем (да и много чем еще). Списки типов. В общем - Loki.

Только беда в том, что не фсе компиляторы поддерживают стандарт на фсе 100% smile

Цитата
Осталось только добавить, что с шаблонами каждый вызов функции превращается в довольно изощренное и долгое действо, что, есстессно, убивает производительность
При современных процессорах и мощности системы вцелом - незначительный проигрышь smile Мы проигрываем в производительности 0,5%, сжираем память, а в проектировании и разработке кода можем выиграть до 100% smile (Загнул конешна, но ладно smile )
Ну и конечно, зависит под что затачиваем софт smile

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)