Какая польза от использования шаблонных функций в c ++? - PullRequest
4 голосов
/ 25 февраля 2010

Имеется класс с функцией шаблона члена, подобной этой:

template <typename t>
class complex
{
public:
    complex(t r, t im);
    template<typename u>
    complex(const complex<u>&);
private:
    //what would be the type of real and imaginary data members here.
}

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

Ответы [ 6 ]

5 голосов
/ 25 февраля 2010

Это дает вам возможность делать преобразования:

complex<int> ci;

complex<float> cf(ci);

Итак, если у вас есть два типа T1 и T2, и вы можете назначить T1 для T2, это позволит назначить *От 1004 * до complex<T2>.

Что касается вопроса в вашем коде (какой тип реальных и мнимых элементов данных здесь):

template <typename t>
class complex
{
...
private:
    t real_part;
    t imaginary_part;
};
4 голосов
/ 25 февраля 2010

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

Например, предположим, что вы работаете на сервере, который получает полдюжины связанных сообщений и сохраняет входящие данные в полдюжине таблиц в базе данных. Простая реализация заключается в реализации 6 функций обработки сообщений (псевдокод):

class MessageProcessor
{
  void OnMessage(const char* msg);
  void ProcessMessage100(Data100* data);
  void ProcessMessage101(Data101* data);
  void ProcessMessage102(Data102* data);
  void ProcessMessage103(Data103* data);
  void ProcessMessage104(Data104* data);
  void ProcessMessage105(Data105* data);
};

MessageProcessor::OnMessage(const char* msg)
{
  unsigned int * msgType = ((unsigned int*)msg);
  switch( *msgType )
  { 
    case 100 :
      ProcessMessage100((Data100*),sg);
      break;
    case 101 :
      ProcessMessage101((Data101*),sg);
      break;
    ::
  }
}

MessageProcessor::ProcessMessage100(Data100* data)
{
  Record100* record = GetRecord100(key);
  record->SetValue(xyz);
}

MessageProcessor::ProcessMessage101(Data101* data)
{
  Record101* record = GetRecord101(key);
  record->SetValue(xyz);
}

: :

Здесь есть возможность обобщить функции ProcessMessage (), поскольку они по сути делают одно и то же:

class MessageProcessor
{
  OnMessage(const char* msg);

  template<class Record, class Data> void Process(Data* data);
};

template<class Record, class Data> 
void MessageProcessor::Process<Record,Data>(Data* data)
{
  Record* record = GetRecord(key);
  record->SetValue(xyz);
}

Функция GetRecord также может быть обобщена, давая кодовую базу с 2 функциями, где их было 12. Это улучшает код, поскольку он проще с меньшим количеством движущихся частей, проще для понимания и обслуживания.

3 голосов
/ 25 февраля 2010

Общее назначение и функциональность шаблонов функций-членов ничем не отличается от обычных шаблонов функций (не являющихся членами). Единственное [несущественное] отличие состоит в том, что функции-члены имеют доступ к неявному параметру this.

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

1 голос
/ 25 февраля 2010

Используя предоставленный вами пример, функция шаблона элемента позволяет вам создать экземпляр complex<T> из complex<U>.

В качестве конкретного примера того, когда это может быть полезно, предположим, что у вас есть complex<double>, но вы хотите complex<float>. Без конструктора типы не связаны, поэтому обычный конструктор копирования не будет работать.

0 голосов
/ 25 февраля 2010

Первые примеры, которые приходят на ум:

  • В некоторых контейнерах-конструкторах (или присваивать методы) для ввода входных итераторов неизвестного типа.

  • std::complex, чтобы разрешить работу с типами, отличными от тех, с которых был создан std::complex.

  • В shared_ptr (std::tr1:: или boost::), чтобы вы могли хранить различные типы указателей в экземпляре общего объекта в куче (для которого можно получить типы указателей).

  • В thread (будь то std:: в c ++ 0x или boost::) для получения функтора неизвестного типа, который будет вызываться экземпляром потока.

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

0 голосов
/ 25 февраля 2010

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...