Где Вы находите шаблоны полезными?

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

16
задан Brian R. Bondy 26 October 2008 в 01:17
поделиться

12 ответов

Я использовал много шаблона кода, главным образом в Повышении и STL, но у меня редко была потребность к запись любой.

Одно из исключений, несколько лет назад, было в программе, которая управляла Windows PE-format EXE files. Компания хотела добавить 64-разрядную поддержку, но ExeFile класс, который я записал для обработки файлов только, работал с 32-разрядными. Код, требуемый управлять 64-разрядной версией, был чрезвычайно идентичен, но это должно было использовать различный тип адреса (64-разрядный вместо 32-разрядного), который заставил две других структуры данных отличаться также.

На основе использования STL единственного шаблона для поддержки и std::string и std::wstring я решил попытаться делать ExeFile шаблон с отличающимися структурами данных и типом адреса как параметры. Было два места, где я все еще должен был использовать #ifdef WIN64 строки (немного отличающиеся требования к обработке), но не было действительно трудно сделать. У нас есть полные 32-и 64-разрядная поддержка в той программе теперь, и использование шаблона означает, что каждая модификация, которую мы сделали с тех пор автоматически, относится к обеим версиям.

8
ответ дан 30 November 2019 в 16:10
поделиться

Общая информация на шаблонах:

Шаблоны полезны каждый раз, когда необходимо использовать тот же код, но воздействующий на различные типы данных, где типы известны во время компиляции. И также когда у Вас есть любой вид контейнерного объекта.

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

Другое очень общее использование для сортировки алгоритмов.

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

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

И теперь на интересный материал:

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

Выезд этот пример шаблонного метапрограммирования из Википедии. Это показывает, как шаблоны могут привыкнуть к [1 113], выполняют код во время компиляции . Поэтому во времени выполнения у Вас есть предрасчетная константа.

template <int N>
struct Factorial 
{
    enum { value = N * Factorial<N - 1>::value };
};

template <>
struct Factorial<0> 
{
    enum { value = 1 };
};

// Factorial<4>::value == 24
// Factorial<0>::value == 1
void foo()
{
    int x = Factorial<4>::value; // == 24
    int y = Factorial<0>::value; // == 1
}
12
ответ дан 30 November 2019 в 16:10
поделиться

Одно место, что я действительно использую шаблоны для создания моего собственного кода, должно реализовать занятия по политике, как описано Andrei Alexandrescu в современном Дизайне C++. В настоящее время я работаю над проектом, который включает ряд классов, которые взаимодействуют с монитором TP Смокинга Oracle BEA\h\h\h.

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

class TpQueue {
public:
   void enqueue(...)
   void dequeue(...)
   ...
}

Однако, поскольку очередь является транзакционной, я должен решить, какое поведение транзакции я хочу; это могло быть сделано отдельно за пределами класса TpQueue, но я думаю, что это более явно и менее подвержено ошибкам, если каждый экземпляр TpQueue имеет свою собственную политику в отношении транзакций. Таким образом, у меня есть ряд классов TransactionPolicy, таких как:

class OwnTransaction {
public:
   begin(...)  // Suspend any open transaction and start a new one
   commit(..)  // Commit my transaction and resume any suspended one
   abort(...)
}

class SharedTransaction {
public:
   begin(...)  // Join the currently active transaction or start a new one if there isn't one
   ...
}

И класс TpQueue переписывается как

template <typename TXNPOLICY = SharedTransaction>
class TpQueue : public TXNPOLICY {
   ...
}

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

TpQueue<SharedTransaction> queue1 ;
TpQueue<OwnTransaction> queue2 ;
7
ответ дан 30 November 2019 в 16:10
поделиться

Я использовал шаблоны (с помощью Повышения. Fusion) для достижения безопасных с точки зрения типов целых чисел для библиотеки гиперграфа, которую я разрабатывал. У меня есть (hyper) граничный идентификатор и идентификатор вершины, оба из которых являются целыми числами. С шаблонами вершина и гиперграничные идентификаторы стали различными типами и использованием того, когда другой ожидался, генерировал ошибку времени компиляции. Сохраненный меня много головной боли, от которой я иначе страдал бы с отладкой на этапе выполнения.

4
ответ дан 30 November 2019 в 16:10
поделиться

Вот один пример из реального проекта. У меня есть функции метода get как это:

bool getValue(wxString key, wxString& value);
bool getValue(wxString key, int& value);
bool getValue(wxString key, double& value);
bool getValue(wxString key, bool& value);
bool getValue(wxString key, StorageGranularity& value);
bool getValue(wxString key, std::vector<wxString>& value);

И затем вариант со значением 'по умолчанию'. Это возвращает значение для ключа, если это существует, или значение по умолчанию, если это не делает. Шаблон сохранил меня от необходимости создать 6 новых функций самого.

template <typename T>
T get(wxString key, const T& defaultValue)
{
    T temp;
    if (getValue(key, temp))
        return temp;
    else
        return defaultValue;
}
3
ответ дан 30 November 2019 в 16:10
поделиться

Шаблоны я, которого используют regulary, являюсь множеством контейнерных классов, повышают интеллектуальные указатели, scopeguards, несколько алгоритмов STL.

Сценарии, в которых я записал шаблоны:

  • пользовательские контейнеры
  • управление памятью, реализовывая безопасность типов и вызов CTor/DTor сверху пустоты * средства выделения
  • общая реализация для перегрузок с различными типами, например,

    bool ContainsNan (плавают *, интервал) bool ContainsNan (дважды *, интервал)

, который оба просто называют (локальный, скрытый) функция помощника

template <typename T>
bool ContainsNanT<T>(T * values, int len) { ... actual code goes here } ;

Определенные алгоритмы, которые независимы от типа, пока тип имеет определенные свойства, например, двоичную сериализацию.

template <typename T>
void BinStream::Serialize(T & value) { ... }

// to make a type serializable, you need to implement
void SerializeElement(BinStream & strean, Foo & element);
void DeserializeElement(BinStream & stream, Foo & element)

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

<час>

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

2
ответ дан 30 November 2019 в 16:10
поделиться

Мы используем COM и принимаем указатель на объект, который может или реализовать другой интерфейс непосредственно или через [IServiceProvider] ( http://msdn.microsoft.com/en-us/library/cc678965 (По сравнению с 85) .aspx) , это предложило мне создавать этого помощника подобная броску функция.

// Get interface either via QueryInterface of via QueryService
template <class IFace>
CComPtr<IFace> GetIFace(IUnknown* unk)
{
    CComQIPtr<IFace> ret = unk; // Try QueryInterface
    if (ret == NULL) { // Fallback to QueryService
        if(CComQIPtr<IServiceProvider> ser = unk)
            ser->QueryService(__uuidof(IFace), __uuidof(IFace), (void**)&ret);
    }
    return ret;
}
2
ответ дан 30 November 2019 в 16:10
поделиться

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

1
ответ дан 30 November 2019 в 16:10
поделиться

Очевидные причины (как предотвращение дублирования кода путем работы на различные типы данных) в стороне, существуют этот действительно прохладный шаблон, который это назвало основанным на политике дизайном. Я задал вопрос [приблизительно 110] политики по сравнению со стратегиями .

Теперь, что так изящно об этой функции. Полагайте запись интерфейса для других для использования. Вы знаете, что Ваш интерфейс будет использоваться, потому что это - модуль в своем собственном домене. Но Вы еще не знаете, как люди собираются использовать его. Основанный на политике дизайн усиливает Ваш код для будущего повторного использования; это делает Вас независимыми от типов данных, на которые полагается конкретная реализация. Код просто "хлебают в".:-)

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

1
ответ дан 30 November 2019 в 16:10
поделиться

Я однажды видел следующий код:

void doSomethingGeneric1(SomeClass * c, SomeClass & d)
{
   // three lines of code
   callFunctionGeneric1(c) ;
   // three lines of code
}

повторился десять раз:

void doSomethingGeneric2(SomeClass * c, SomeClass & d)
void doSomethingGeneric3(SomeClass * c, SomeClass & d)
void doSomethingGeneric4(SomeClass * c, SomeClass & d)
// Etc

Каждая функция, имеющая те же 6 строк кода, копируют/вставляют, и каждый раз вызывая другую функцию callFunctionGenericX с тем же суффиксом числа.

не было никакого способа осуществить рефакторинг все это в целом. Таким образом, я сохранил рефакторинг локальным.

я изменил код этот путь (из памяти):

template<typename T>
void doSomethingGenericAnything(SomeClass * c, SomeClass & d, T t)
{
   // three lines of code
   t(c) ;
   // three lines of code
}

И измененный существующий код с:

void doSomethingGeneric1(SomeClass * c, SomeClass & d)
{
   doSomethingGenericAnything(c, d, callFunctionGeneric1) ;
}

void doSomethingGeneric2(SomeClass * c, SomeClass & d)
{
   doSomethingGenericAnything(c, d, callFunctionGeneric2) ;
}

И т.д.

Это несколько угоняет шаблонную вещь, но в конце, я предполагаю, что это лучше, чем игра с typedefed указателями функции или макросами использования.

1
ответ дан 30 November 2019 в 16:10
поделиться

Я лично использовал Любопытно Повторяющийся Шаблонный Шаблон в качестве средства осуществления некоторой формы нисходящего дизайна и восходящей реализации. Примером была бы спецификация для универсального обработчика, где определенные требования и на форме и на интерфейсе осуществляются на производных типах во время компиляции. Это выглядит примерно так:

template <class Derived>
struct handler_base : Derived {
  void pre_call() {
    // do any universal pre_call handling here
    static_cast<Derived *>(this)->pre_call();
  };

  void post_call(typename Derived::result_type & result) {
    static_cast<Derived *>(this)->post_call(result);
    // do any universal post_call handling here
  };

  typename Derived::result_type
  operator() (typename Derived::arg_pack const & args) {
    pre_call();
    typename Derived::result_type temp = static_cast<Derived *>(this)->eval(args);
    post_call(temp);
    return temp;
  };

};

Что-то вроде этого может использоваться затем, чтобы удостовериться, что Ваши обработчики происходят из этого шаблона и осуществляют нисходящий дизайн и затем допускают восходящую настройку:

struct my_handler : handler_base<my_handler> {
  typedef int result_type; // required to compile
  typedef tuple<int, int> arg_pack; // required to compile
  void pre_call(); // required to compile
  void post_call(int &); // required to compile
  int eval(arg_pack const &); // required to compile
};

Это тогда позволяет Вам иметь универсальные полиморфные функции, которые имеют дело с только handler_base<> производные типы:

template <class T, class Arg0, class Arg1>
typename T::result_type
invoke(handler_base<T> & handler, Arg0 const & arg0, Arg1 const & arg1) {
  return handler(make_tuple(arg0, arg1));
};
1
ответ дан 30 November 2019 в 16:10
поделиться

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

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

1
ответ дан 30 November 2019 в 16:10
поделиться
Другие вопросы по тегам:

Похожие вопросы: