Как можно использовать параметры шаблона шаблона?
Я видел несколько примеров C++, использующих 9X_templates параметры шаблона шаблона (то есть шаблоны, которые 9X_template принимают шаблоны в качестве параметров) для 9X_cpp создания классов на основе политик. Как 9X_cxx еще можно использовать эту технику?
- Я пришел с другого направления (FP, ...
Ответ #1
Ответ на вопрос: Как можно использовать параметры шаблона шаблона?
Я думаю, вам нужно использовать синтаксис 9X_templates шаблона шаблона для передачи параметра, тип 9X_template которого является шаблоном, зависящим от 9X_template другого шаблона, например этого:
template class H, class S>
void f(const H &value) {
}
Здесь H
- шаблон, но 9X_c++ я хотел, чтобы эта функция работала со всеми 9X_templates специализациями H
.
ПРИМЕЧАНИЕ. Я программировал на C++ много 9X_cxx лет, и мне это понадобилось только один 9X_cpp раз. Я считаю, что это редко используемая 9X_template-templates функция (конечно, удобная, когда она вам 9X_template-templates нужна!).
Я пытался придумать хорошие примеры, и, честно 9X_cpp говоря, в большинстве случаев в этом нет 9X_template необходимости, но давайте придумаем пример. Представим, что 9X_cxx std::vector
не имеет typedef value_type
.
Итак, как бы вы написали функцию, которая 9X_c++ может создавать переменные правильного типа 9X_c++ для векторных элементов? Это сработает.
template class V, class T, class A>
void f(V &v) {
// This can be "typename V::value_type",
// but we are pretending we don't have it
T temp = v.back();
v.pop_back();
// Do some work on temp
std::cout << temp << std::endl;
}
ПРИМЕЧАНИЕ. std::vector
имеет 9X_templates два параметра шаблона, тип и распределитель, поэтому 9X_c++ нам пришлось принять их оба. К счастью, из-за 9X_cpp вывода типа нам не нужно явно указывать 9X_template-templates точный тип.
который можно использовать так:
f(v); // v is of type std::vector using any allocator
или 9X_templates еще лучше, мы можем просто использовать:
f(v); // everything is deduced, f can deal with a vector of any type!
ОБНОВЛЕНИЕ. Даже 9X_c++ этот надуманный пример, хотя и является 9X_template-templates иллюстративным, больше не является прекрасным 9X_template-templates из-за того, что в C++ 11 введен auto
. Теперь 9X_templates ту же функцию можно записать как:
template
void f(Cont &v) {
auto temp = v.back();
v.pop_back();
// Do some work on temp
std::cout << temp << std::endl;
}
именно 9X_templates так я бы предпочел написать этот тип кода.
- Что ж, вам не нужно предоставлять распределитель. Важно то, что параметр шаблона шаблона был определен с правильным количеством аргументов. Но функция не должна заботиться об их «типах» или значении, в C++ ...
Ответ #2
Ответ на вопрос: Как можно использовать параметры шаблона шаблона?
На самом деле, вариант использования параметров 9X_templates шаблона достаточно очевиден. Как только 9X_c++ вы узнаете, что в C++ stdlib есть зияющая 9X_templates дыра в том, что не определены операторы 9X_c++ вывода потока для стандартных типов контейнеров, вы 9X_template-templates можете приступить к написанию чего-то вроде:
template
static inline std::ostream& operator<<(std::ostream& out, std::list const& v)
{
out << '[';
if (!v.empty()) {
for (typename std::list::const_iterator i = v.begin(); ;) {
out << *i;
if (++i == v.end())
break;
out << ", ";
}
}
out << ']';
return out;
}
Тогда 9X_cpp вы поймете, что код для вектора такой же, для 9X_cpp forward_list такой же, на самом деле, даже 9X_templates для множества типов карт он остается неизменным. Эти 9X_templates классы шаблонов не имеют ничего общего, кроме 9X_cxx метаинтерфейса / протокола, и использование 9X_template-templates параметра шаблона шаблона позволяет зафиксировать 9X_template-templates общность во всех из них. Однако прежде чем 9X_cpp приступить к написанию шаблона, стоит проверить 9X_cpp ссылку, чтобы вспомнить, что контейнеры 9X_cxx последовательности принимают 2 аргумента 9X_cxx шаблона - для типа значения и распределителя. Хотя 9X_c++ распределитель установлен по умолчанию, мы 9X_cpp все равно должны учитывать его существование 9X_cxx в нашем шаблоне operator <<:
template class Container, class V, class A>
std::ostream& operator<<(std::ostream& out, Container const& v)
...
Вуаля, это будет 9X_cpp работать автоматически для всех нынешних 9X_cxx и будущих контейнеров последовательностей, придерживающихся 9X_templates стандартного протокола. Чтобы добавить карты 9X_cxx в микс, нужно взглянуть на ссылку, чтобы 9X_cpp заметить, что они принимают 4 параметра 9X_template-templates шаблона, поэтому нам понадобится другая 9X_cxx версия оператора << выше с параметром шаблона 9X_template-templates шаблона с 4 аргументами. Мы также увидели 9X_cpp бы, что std: pair пытается отобразить с 9X_template-templates помощью 2-arg operator << для типов последовательностей, которые 9X_cxx мы определили ранее, поэтому мы предоставим 9X_templates специализацию только для std :: pair.
Между 9X_template-templates прочим, с C + 11, который допускает вариативные 9X_cxx шаблоны (и, следовательно, должен разрешать 9X_cpp вариативные аргументы шаблона шаблона), можно 9X_templates было бы иметь один оператор <<, чтобы управлять 9X_template ими всеми. Например:
#include
#include
#include
#include
template class C, class... Args>
std::ostream& operator <<(std::ostream& os, const C& objs)
{
os << __PRETTY_FUNCTION__ << '\n';
for (auto const& obj : objs)
os << obj << ' ';
return os;
}
int main()
{
std::vector vf { 1.1, 2.2, 3.3, 4.4 };
std::cout << vf << '\n';
std::list lc { 'a', 'b', 'c', 'd' };
std::cout << lc << '\n';
std::deque di { 1, 2, 3, 4 };
std::cout << di << '\n';
return 0;
}
Вывод
std::ostream &operator<<(std::ostream &, const C &) [T = float, C = vector, Args = >]
1.1 2.2 3.3 4.4
std::ostream &operator<<(std::ostream &, const C &) [T = char, C = list, Args = >]
a b c d
std::ostream &operator<<(std::ostream &, const C &) [T = int, C = deque, Args = >]
1 2 3 4
- Это самый пробуждающий для меня ответ в шаблонах C++. @WhozCraig Как вы узнали ...
Ответ #3
Ответ на вопрос: Как можно использовать параметры шаблона шаблона?
Вот простой пример, взятый из 'Modern C++ Design - Generic Programming and Design Patterns Applied' Андрея Александреску:
Он 9X_template-templates использует классы с параметрами шаблона 9X_template шаблона для реализации шаблона политики:
// Library code
template class CreationPolicy>
class WidgetManager : public CreationPolicy
{
...
};
Он 9X_template объясняет: Обычно класс хоста уже знает или может легко вывести аргумент шаблона класса политики. В приведенном выше примере WidgetManager всегда управляет объектами типа Widget, поэтому требование, чтобы пользователь снова указывал Widget при создании экземпляра CreationPolicy, является избыточным и потенциально опасным. В этом случае код библиотеки может использовать параметры шаблона шаблона для определения политик.
В результате клиентский код может 9X_templates использовать WidgetManager более элегантно:
typedef WidgetManager MyWidgetMgr;
Вместо 9X_cpp более громоздкого и подверженного ошибкам 9X_templates способа, который потребовалось бы для определения 9X_template-templates без аргументов шаблона шаблона:
typedef WidgetManager< MyCreationPolicy > MyWidgetMgr;
- В вопросе конкретно запрашиваются примеры, отличные от шабло ...
Ответ #4
Ответ на вопрос: Как можно использовать параметры шаблона шаблона?
Вот еще один практический пример из моего 9X_template CUDA Convolutional neural network library. У меня есть следующий шаблон класса:
template class Tensor
, который 9X_template-templates на самом деле реализует манипуляции с n-мерными 9X_template-templates матрицами. Также существует шаблон дочернего 9X_template класса:
template class TensorGPU : public Tensor
, который реализует те же функции, но 9X_cpp в графическом процессоре. Оба шаблона могут 9X_cxx работать со всеми основными типами, такими 9X_template как float, double, int и т. Д. А еще у меня 9X_template-templates есть шаблон класса (упрощенный):
template class TT, class T> class CLayerT: public Layer >
{
TT weights;
TT inputs;
TT connection_matrix;
}
Причина, по 9X_templates которой здесь используется синтаксис шаблона 9X_c++ шаблона, заключается в том, что я могу объявить 9X_c++ реализацию класса
class CLayerCuda: public CLayerT
который будет иметь как 9X_template-templates веса, так и входные данные типа float и 9X_cpp на GPU, но connection_matrix всегда будет 9X_templates int, либо на CPU (указав TT = Tensor), либо 9X_c++ на GPU (указав TT = TensorGPU).
Ответ #5
Ответ на вопрос: Как можно использовать параметры шаблона шаблона?
Допустим, вы используете CRTP для предоставления 9X_template-templates «интерфейса» для набора дочерних шаблонов; и 9X_templates родительский, и дочерний элементы являются 9X_template-templates параметрическими в другом (-ых) аргументе 9X_cxx (-ах) шаблона:
template class interface {
void do_something(VALUE v) {
static_cast(this)->do_something(v);
}
};
template class derived : public interface {
void do_something(VALUE v) { ... }
};
typedef interface, int> derived_t;
Обратите внимание на дублирование 9X_template int, которое на самом деле является параметром 9X_template одного и того же типа, указанным для обоих 9X_templates шаблонов. Вы можете использовать шаблон 9X_cpp шаблона для DERIVED, чтобы избежать этого 9X_template дублирования:
template class DERIVED, typename VALUE> class interface {
void do_something(VALUE v) {
static_cast*>(this)->do_something(v);
}
};
template class derived : public interface {
void do_something(VALUE v) { ... }
};
typedef interface derived_t;
Обратите внимание, что вы исключаете 9X_c++ прямую передачу других параметров шаблона 9X_template-templates производному шаблону; "интерфейс" по-прежнему их получает.
Это 9X_template-templates также позволяет вам создавать определения 9X_cpp типов в «интерфейсе», которые зависят от 9X_cxx параметров типа, которые будут доступны 9X_template-templates из производного шаблона.
Приведенный выше 9X_cxx typedef не работает, потому что вы не можете 9X_template ввести typedef для неопределенного шаблона. Однако 9X_template это работает (а в C++ 11 есть встроенная 9X_c++ поддержка шаблонов typedefs):
template
struct derived_interface_type {
typedef typename interface type;
};
typedef typename derived_interface_type::type derived_t;
Вам понадобится 9X_template один производный_интерфейс_тип для каждого 9X_template-templates экземпляра производного шаблона, к сожалению, если 9X_cxx нет другого трюка, которому я еще не научился.
Ответ #6
Ответ на вопрос: Как можно использовать параметры шаблона шаблона?
Вот с чем я столкнулся:
template
class B
{
A& a;
};
template
class A
{
B b;
};
class AInstance : A>>>>>>>
{
};
Можно решить, чтобы:
template
class B
{
A& a;
};
template< template class B>
class A
{
B b;
};
class AInstance : A //happy
{
};
или 9X_template (рабочий код):
template
class B
{
public:
A* a;
int GetInt() { return a->dummy; }
};
template< template class B>
class A
{
public:
A() : dummy(3) { b.a = this; }
B b;
int dummy;
};
class AInstance : public A //happy
{
public:
void Print() { std::cout << b.GetInt(); }
};
int main()
{
std::cout << "hello";
AInstance test;
test.Print();
}
Ответ #7
Ответ на вопрос: Как можно использовать параметры шаблона шаблона?
Вот одно обобщение из того, что я только 9X_templates что использовал. Я публикую его, так как 9X_cxx это очень простой пример, и он демонстрирует 9X_cxx практический вариант использования вместе 9X_c++ с аргументами по умолчанию:
#include
template class Alloc final { /*...*/ };
template class allocator=Alloc> class MyClass final {
public:
std::vector> field0;
std::vector> field1;
};
Ответ #8
Ответ на вопрос: Как можно использовать параметры шаблона шаблона?
В решении с вариативными шаблонами, предоставленным 9X_cpp pfalcon, мне было трудно на самом деле специализировать 9X_template оператор ostream для std :: map из-за жадной 9X_templates природы вариативной специализации. Вот небольшая 9X_template доработка, которая у меня сработала:
#include
#include
#include
#include
#include
Ответ #9
Ответ на вопрос: Как можно использовать параметры шаблона шаблона?
Это улучшает читаемость вашего кода, обеспечивает 9X_c++ дополнительную безопасность типов и экономит 9X_templates некоторые усилия компилятора.
Допустим, вы 9X_template хотите распечатать каждый элемент контейнера, вы 9X_templates можете использовать следующий код без параметра 9X_cpp шаблона шаблона
template void print_container(const T& c)
{
for (const auto& v : c)
{
std::cout << v << ' ';
}
std::cout << '\n';
}
или с параметром шаблона 9X_template шаблона
template< template class ContainerType, typename ValueType, typename AllocType>
void print_container(const ContainerType& c)
{
for (const auto& v : c)
{
std::cout << v << ' ';
}
std::cout << '\n';
}
Предположим, вы передаете целое число, например 9X_templates print_container(3)
. В первом случае экземпляр шаблона будет 9X_c++ создан компилятором, который будет жаловаться 9X_cpp на использование c
в цикле for, последний 9X_cpp не будет создавать экземпляр шаблона вообще, поскольку 9X_cxx не может быть найден подходящий тип.
Вообще 9X_cxx говоря, если ваш класс / функция шаблона 9X_c++ предназначен для обработки класса шаблона 9X_templates как параметра шаблона, лучше прояснить это.
Ответ #10
Ответ на вопрос: Как можно использовать параметры шаблона шаблона?
Я использую его для версионных типов.
Если 9X_template у вас есть тип, версионированный с помощью 9X_cxx шаблона, такого как MyType
, вы можете написать 9X_cxx функцию, в которой вы можете фиксировать 9X_cxx номер версии:
template T, uint8_t Version>
Foo(const T& obj)
{
assert(Version > 2 && "Versions older than 2 are no longer handled");
...
switch (Version)
{
...
}
}
Таким образом, вы можете делать 9X_templates разные вещи в зависимости от версии передаваемого 9X_c++ типа вместо того, чтобы иметь перегрузку 9X_template для каждого типа.
У вас также могут быть 9X_cxx функции преобразования, которые принимают 9X_template-templates MyType
и возвращают MyType
общим способом и даже рекурсивно 9X_c++ рекурсируют их, чтобы иметь функцию ToNewest()
, которая 9X_cpp возвращает последнюю версию типа из любой 9X_template-templates более старой версии (очень полезно для журналы, которые 9X_templates могли быть сохранены некоторое время назад, но 9X_cxx должны обрабатываться с помощью новейшего 9X_cxx инструмента сегодняшнего дня).
-
3
-
11
-
11
-
27
-
17
-
8
-
12
-
9
-
9
-
5
-
7
-
23
-
13
-
20
-
9
-
28
-
5
-
5
-
2
-
2
-
15
-
4
-
2
-
8
-
8
-
8
-
4
-
4
-
9
-
7
-
3
-
13
-
8
-
2
-
4
-
4
-
10
-
8
-
3
-
3
-
8
-
4
-
9
-
11
-
9
-
2
-
3
-
3
-
3
-
6