1

Рассмотрим следующую установку:Альтернативы для станд :: 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 версии узла в графе, но разные по разветвленным и неразветвленным графам). Должен ли я:

  1. Дублировать код?
  2. Использование std::enable_if hack?

    1. Дублирование кода дублирует ошибки, поэтому оно не является оптимальным.
    2. std :: enable_if создает плохие сообщения об ошибках в моем случае.

Есть ли умное решение проблемы, которая заставит f принимать константные и не константные узлы?

+1

Почему не просто 'template void f (Graph )' и пусть 'T' будет выведено соответствующим образом? Вы всегда можете легко извлечь тип узла с помощью класса признаков. –

+0

Почему 'Graph < node_t >' и 'Graph >' тот же самый шаблон, если они имеют разные реализации, интерфейсы и используются по-разному? Или есть функции, которые относятся к ним одинаково? Вы можете написать фабричный шаблон, который возвращает другой тип на основе, если это терминал или нет, например. – Yakk

+0

@Yakk: Есть две причины: 1. «Граф» получается из 'Branch <>', который является оберткой 'std :: tuple'. Поскольку 'std :: tuple <>' не является нулевым размером, я думаю, что пустая оптимизация базы не будет применяться. 2. Рекурсивные функции, которые пересекают «График» и завершают их на терминальном узле, требуют перегрузки функции. Перегрузка для 'Graph >' не очень отличается от формы «Graph », а последняя производит более короткие ошибки и более явна в намерениях. @TC: Это отличная идея, за которую я пошел. Спасибо, как всегда, это должно быть опубликовано как ответ. – tsuki

ответ

1

Вместо того, чтобы использовать параметр шаблона шаблона и иметь Gazillion перегрузки, просто используйте параметр шаблона типа:

template<class T> void f(Graph<T>) { /*...*/ } 

T будет выведен быть Node<Foo>, vNode<Foo> или const Node<Foo> и т.д. в зависимости от обстоятельств. Если значение Node связано с vNode, вы всегда можете извлечь тип узла с помощью простого класса признаков. Аналогичным образом, вы можете использовать static_assert вместе с классом признаков, чтобы гарантировать, что T является специализацией Node или vNode.

Смежные вопросы