Самые важные вещи о шаблонах C ++… извлеченные уроки - PullRequest
14 голосов
/ 01 марта 2009

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

Я начинаю реализовывать большую часть своей библиотеки / API с использованием шаблонов и хотел бы собрать наиболее распространенные шаблоны, советы и т. Д., Найденные на практике.

Позвольте мне формализовать вопрос: что самое важное вы узнали о шаблонах?

Пожалуйста, попробуйте привести примеры - это будет легче понять, в отличие от запутанных и чрезмерно сухих описаний

Спасибо

Ответы [ 12 ]

18 голосов
/ 01 марта 2009

С «Исключительный стиль C ++», позиция 7: разрешение перегрузки функции происходит до специализации шаблонов. Не смешивайте перегруженные функции и специализации шаблонных функций, иначе вас ждет неприятный сюрприз, когда функция действительно вызывается.

template<class T> void f(T t) { ... }   // (a)
template<class T> void f(T *t) { ... }  // (b)
template<> void f<int*>(int *t) { ... } // (c)
...
int *pi; f(pi); // (b) is called, not (c)!

Сверху Элемент 7 :

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

Дело 1:

template<class T> void f(T t) { ... }  // (a)
template<class T> void f(T *t) { ... } // (b)
template<> void f(int *t) { ... }      // (c) - specializes (b)
...
int *pi; f(pi); // (c) is called

Дело 2:

template<class T> void f(T t) { ... }  // (a)
template<> void f(int *t) { ... }      // (c) - specializes (a)
template<class T> void f(T *t) { ... } // (b)
...
int *pi; f(pi); // (b) is called
7 голосов
/ 01 марта 2009

Это может быть не популярно, но я думаю, что это нужно сказать.

Шаблоны сложные.

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

И самое главное, держитесь подальше от шаблонного метапрограммирования ...

5 голосов
/ 01 марта 2009

Я бы сказал, что Любопытно повторяющийся шаблонный шаблон (CRTP) Коплина - это один шаблонный трюк, к которому я снова и снова обращаюсь. По сути, это позволяет вам вводить статически настраиваемую функциональность в производный класс, наследуя его от базового класса, параметризованного в имени производного класса. Потрясающе, но удивительно полезно (некоторые называют это статическим полиморфизмом).

Кроме того, я прислушаюсь к совету Нила Баттеруорта о том, чтобы прочитать «Шаблоны C ++» и добавлю Современный дизайн C ++ Александреску .

4 голосов
/ 03 марта 2009

Одна распространенная ошибка в том, что конструктор шаблона или оператор присваивания не будут подавлять сгенерированный компилятором один:

template <typename T>
class A {
public:
  template <typename S>
  A(A<S> const &);

  template <typename S>
  A & operator=(A<S> const &);

private:
  int * i;
}; 

Хотя эти функции выглядят как конструктор копирования и оператор присваивания копии, компилятор не видит его таким образом и все равно генерирует неявные версии. В результате любые действия, выполняемые этими функциями (например, глубокое копирование члена), не будут выполняться, когда объект копируется или назначается из того же типа:

void foo (A<int>);

void bar () {
  A<int> a1;
  foo (a1);   // Implicitly generated copy ctor called

  A<long> a2;
  foo (a2);   // Template ctor called.

  A<int> a3;
  a3 = a1;   // Implicitly generated copy assignment operator called

  a3 = a2;   // Template assignment operator called
}

Причиной такого поведения является специальное правило разрешения перегрузки (13.3.3):

Учитывая эти определения, жизнеспособный функция F1 определена как лучшая функция, чем другая жизнеспособная функция F2 если для всех аргументов i, ICSi (F1) не хуже, чем последовательность преобразования ICSi (F2), а затем

[...]

- F1 - не шаблонная функция и F2 - это шаблон функции специализация или, если не так,

В приведенных выше примерах разрешение перегрузки видит две функции с одинаковой сигнатурой, одна из которых является шаблоном. Не шаблонная функция (неявно сгенерированный конструктор копирования / оператор копирования) побеждает и так называется.

4 голосов
/ 01 марта 2009

Шаблон Совет дня: Знаете ли вы, что можете специализировать выбранные функции создания шаблонов:

#include <iostream>
#include <vector>

namespace std {
    template<>
    void vector<int>::clear() {
    std::cout << "Clearing..." << std::endl;
    resize(0);
    }
}

int main() {
    std::vector<int> v;
    v.push_back(1);
    v.clear();
}

Выходы: Очистка ...

4 голосов
/ 01 марта 2009

Этот вопрос немного напоминает: «Я собираюсь реализовать большую часть своей библиотеки с использованием функций, каковы распространенные ошибки при использовании функций?» Трудно придумать разумные ответы на такие вопросы, но вот мой совет - прочитайте хорошую книгу. Я рекомендую " C ++ Templates " от Vandevoorde & Josuttis,

2 голосов
/ 01 марта 2009

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

В целом, при вводе текста полезно думать о том, что собирается делать компилятор, и как будет генерироваться код для каждого типа.

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

Наконец, когда нет выхода, прочитайте эти сообщения об ошибках компиляции! Сначала они могут выглядеть довольно страшно, но они действительно полезны. Возможно, сначала извлекая первый, скопировав его в текстовом редакторе и сделав его красивым, вы привыкнете к ним, и он быстро станет вторым натуром для чтения.

2 голосов
/ 01 марта 2009

Прочитайте книги Майерса "Эффективные STL и C ++" и "Современный дизайн C ++ Александреску".

Мейерс расскажет вам, как легко совершать ошибки и как их избежать. Александреску знакомит вас с моделью программирования на основе шаблонов, в которой вы должны спросить: «Действительно ли это хорошая идея?» вся книга.

2 голосов
/ 01 марта 2009

Вот несколько правил:

  1. Не пишите никаких шаблонов, если вы не пишете очень, очень универсальную библиотеку (STL и Boost - два ярких примера).
  2. Не создавайте экземпляры какого-либо нетривиального шаблона слишком много раз. Создание огромных шаблонных классов особенно излишне. Вы должны рассмотреть возможность использования наследования и полиморфизма (я имею в виду простой способ использования виртуальных функций).
  3. Если вы пишете какие-либо шаблоны, знание того, когда использовать const, mutable и volatile, сэкономит пользователям шаблона как время компиляции, так и время выполнения.
  4. Если вы создаете какие-либо шаблоны, используйте хороший компилятор.
2 голосов
/ 01 марта 2009

STL - ваш друг.

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