Самые важные вещи о шаблонах С++... извлеченный урок
Каковы наиболее важные вещи, которые вы знаете о шаблонах: скрытые функции, распространенные ошибки, лучшие и наиболее полезные практики, советы... распространенные ошибки/надзор/допущения
Я начинаю реализовывать большую часть своей библиотеки /API с помощью шаблонов и собираюсь собирать наиболее распространенные шаблоны, советы и т.д., которые можно найти на практике.
Позвольте мне оформить вопрос: что самое главное, что вы узнали о шаблонах?
Попробуйте привести примеры - было бы легче понять, в отличие от извитых и чрезмерно сухих описаний
Спасибо
Ответы
Ответ 1
От "Исключительный стиль С++", функция перегрузки функции 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
Ответ 2
Это может быть не очень популярно, но я думаю, что это нужно сказать.
Шаблоны сложны.
Они невероятно сильны, но используют их с умом. Не сходите с ума, не слишком много аргументов шаблона... Не слишком много специализаций... Помните, что другие программисты тоже должны это прочитать.
И самое главное, избегайте метапрограммирования шаблонов...
Ответ 3
Я бы сказал, что Coplien Любопытно, что повторяющийся шаблон шаблона (CRTP) - это единственный шаблонный трюк, который я нахожу себе снова и снова еще раз. По сути, это позволяет вводить статически настроенные функции в производный класс, наследуя от базового класса, который параметризуется в имени производного класса. Умение ошеломляет, но удивительно полезно (некоторые называют его статическим полиморфизмом).
Кроме того, я позабочусь о совете Нила Баттерворта, чтобы прочитать "С++ Templates" и добавить Alexandrescu Modern С++ Design.
Ответ 4
Этот вопрос немного напоминает "Я собираюсь реализовать большую часть своей библиотеки, используя функции, каковы распространенные ошибки при использовании функций?" Трудно придумать разумные ответы на такие вопросы, но здесь мой совет - прочитать хорошую книгу. Я рекомендую " С++ Templates" от Vandevoorde и Josuttis,
Ответ 5
Одна из распространенных ошибок заключается в том, что конструктор шаблонов или оператор присваивания не будут подавлять генерируемый компилятором:
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 - шаблон функции специализация, или, если не это,
В приведенных выше примерах разрешение перегрузки видит две функции с одной и той же сигнатурой, одна из которых является шаблоном. Функция non template (неявно созданная копия/оператор присваивания копий) выигрывает и так называется.
Ответ 6
Совет по шаблону дня:
Знаете ли вы, что вы можете специализировать выбранные функции создания экземпляров шаблонов:
#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();
}
Выходы:
Clearing...
Ответ 7
STL является вашим другом.
Ответ 8
Вот несколько правил:
- Не пишите никаких шаблонов, если вы не пишете очень и очень общую библиотеку (STL и Boost - это два выдающихся примера).
- Не создавайте экземпляр какого-либо нетривиального шаблона слишком много раз. Создание экземпляров огромных классов шаблонов особенно утомительно. Вы должны рассмотреть возможность использования наследования и полиморфизма (простой способ, я имею в виду использование виртуальных функций).
- Если вы пишете какие-либо шаблоны, зная, когда использовать
const
, mutable
и volatile
будут сохранять пользователей шаблона как для компиляции, так и для выполнения.
- Если вы создаете какие-либо шаблоны, используйте хороший компилятор.
Ответ 9
Читайте Meyers Эффективные книги STL и С++, а также Alexandrescu Modern С++ Design.
Мейерс расскажет вам о простых ошибках и о том, как их избежать. Alexandrescu представляет вам шаблонную модель программирования, которая должна спросить вас: "Это действительно хорошая идея?" вся книга.
Ответ 10
Я очень часто использую шаблоны, чтобы избежать дублирования кода и повысить безопасность с помощью проверки компиляции.
В общем, это помогает мыслить при наборе того, что будет делать компилятор, и как будет генерироваться код для каждого типа.
Быть очень итеративным для разработки и создания сложности шаблона мало-помалу помогло мне избежать погружения в компиляцию сообщений об ошибках. Не забудьте сохранить простой (или макет) экземпляр шаблона где-нибудь, иначе у вас могут быть неприятные сюрпризы, когда вы создаете шаблон монстра в первый раз.
Наконец, когда нет выхода, прочитайте эти компиляционные сообщения об ошибках! Сначала они могут выглядеть довольно страшно, но они действительно полезны. Возможно, сначала извлечение первого, копирование его в текстовом редакторе и его правильное отображение помогут привыкнуть к ним, и он быстро становится второй натурой для чтения.
Ответ 11
Важно понимать раздельную компиляцию и возможность увеличения размера исполняемого файла. Если вы создадите экземпляр шаблона с тем же типом в нескольких файлах на С++, вы получите тип, воспроизводимый несколько раз, по крайней мере, на некоторых компиляторах.
Ответ 12
Я использовал С++ и шаблоны много, включая более продвинутое метапрограммирование шаблонов, и я чувствую, что их полезность переоценена. Они были первоначально добавлены на язык С++, а также после создания С++, чтобы использовать универсальные возможности программирования. Это просто позволяет сосредоточиться на логике кода без учета типов, что делает код более понятным и многоразовым.
Моя философия программирования заключается в том, чтобы понять первоначальную цель и дизайн языка и его особенности, чтобы действительно оценить язык. Я чувствую, что метапрограммирование шаблона - это бастардирование шаблонов, и его следует избегать. Шаблоны, однако, полезны для определения более общих типов более высокого уровня, например, для кортежей.