Подтвердить что ты не робот

Самые важные вещи о шаблонах С++... извлеченный урок

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

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

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

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

Спасибо

4b9b3361

Ответ 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

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

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