Рассмотрим следующую установку:Альтернативы для станд :: enable_if и явной перегрузкой для шаблона параметров шаблона
template< typename Held >
class Node{
//...
};
template< typename Held >
class vNode{
//...
};
template <typename... Graphs>
class Branch{
//...
};
template <typename...> class Graph; // undefined
template<
typename node_t
> class Graph<node_t>{ //specialization for an ending node
//...
};
template<
typename node_t,
typename... Graphs
> class Graph< node_t, Branch< Graphs...> >{ //specialization for a mid-graph node
//...
};
template<
template <typename> class node_t,
typename Held
> void f(Graph< Node<Held> >) {
//stuff A on a node
}
template<
template <typename> class node_t,
typename Held
> void f(Graph< const Node<Held> >) {
//stuff A on a const node
}
template<
template <typename> class node_t,
typename Held
> void f(Graph< vNode<Held> >) {
//stuff B on a virtual node
}
template<
template <typename> class node_t,
typename Held
> void f(Graph< const vNode<Held> >) {
//stuff B on a virtual const node
}
template<
template <typename> class node_t,
typename Held,
typename... Graphs
> void f(Graph< Node<Held>, Branch<Graphs...>>) {
//stuff C on a node with a branch
}
template<
template <typename> class node_t,
typename Held,
typename... Graphs
> void f(Graph< const Node<Held>, Branch<Graphs...> >) {
//stuff C on a const node with a branch
}
template<
template <typename> class node_t,
typename Held,
typename... Graphs
> void f(Graph< vNode<Held>, Branch<Graphs...> >) {
//stuff D on a virtual node with a branch
}
template<
template <typename> class node_t,
typename Held,
typename... Graphs
> void f(Graph< const vNode<Held>, Branch<Graphs...> >) {
//stuff D on a virtual const node with a branch
}
Другими словами - я создаю тип, который представляет собой график. Узлы могут быть нормальными или виртуальными, const и non-const. График может содержать один узел или узел и ветвь графиков.
Когда я создаю функцию f
Я хочу, чтобы она была const-нейтралью (делайте то же самое в const и не-const версии узла в графе, но разные по разветвленным и неразветвленным графам). Должен ли я:
- Дублировать код?
Использование
std::enable_if
hack?- Дублирование кода дублирует ошибки, поэтому оно не является оптимальным.
- std :: enable_if создает плохие сообщения об ошибках в моем случае.
Есть ли умное решение проблемы, которая заставит f
принимать константные и не константные узлы?
Почему не просто 'template void f (Graph )' и пусть 'T' будет выведено соответствующим образом? Вы всегда можете легко извлечь тип узла с помощью класса признаков. –
Почему 'Graph < node_t >' и 'Graph>' тот же самый шаблон, если они имеют разные реализации, интерфейсы и используются по-разному? Или есть функции, которые относятся к ним одинаково? Вы можете написать фабричный шаблон, который возвращает другой тип на основе, если это терминал или нет, например. –
Yakk
@Yakk: Есть две причины: 1. «Граф» получается из 'Branch <>', который является оберткой 'std :: tuple'. Поскольку 'std :: tuple <>' не является нулевым размером, я думаю, что пустая оптимизация базы не будет применяться. 2. Рекурсивные функции, которые пересекают «График» и завершают их на терминальном узле, требуют перегрузки функции. Перегрузка для 'Graph>' не очень отличается от формы «Graph », а последняя производит более короткие ошибки и более явна в намерениях. @TC: Это отличная идея, за которую я пошел. Спасибо, как всегда, это должно быть опубликовано как ответ. –
tsuki