C++ std::enable_if和模板参数的显式重载的备选方案

C++ std::enable_if和模板参数的显式重载的备选方案,c++,templates,c++11,template-meta-programming,overload-resolution,C++,Templates,C++11,Template Meta Programming,Overload Resolution,请考虑以下设置: template< typename Held > class Node{ //... }; template< typename Held > class vNode{ //... }; template <typename... Graphs> class Branch{ //... }; template <typename...> class Graph; // undefined template&l

请考虑以下设置:

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
}
template
类节点{
//...
};
模板
类vNode{
//...
};
模板
班支部{
//...
};
模板类图;//未定义
模板<
类型名称节点
>类图{//结束节点的专门化
//...
};
模板<
类型名节点,
类型名。。。图
>类图>{//中间图节点的专门化
//...
};
模板<
模板类节点,
保留的字体名
>void f(图){
//在节点上填充
}
模板<
模板类节点,
保留的字体名
>空f(图形<常量节点>){
//在常量节点上填充
}
模板<
模板类节点,
保留的字体名
>空f(图形){
//在虚拟节点上填充B
}
模板<
模板类节点,
保留的字体名
>空f(图){
//在虚拟常量节点上填充B
}
模板<
模板类节点,
字体名称保持不变,
类型名。。。图
>空f(图<节点,分支>){
//在带有分支的节点上填充C
}
模板<
模板类节点,
字体名称保持不变,
类型名。。。图
>void f(图<常量节点,分支>){
//在具有分支的常量节点上填充C
}
模板<
模板类节点,
字体名称保持不变,
类型名。。。图
>空f(图){
//在带有分支的虚拟节点上填充D
}
模板<
模板类节点,
字体名称保持不变,
类型名。。。图
>空f(图){
//在具有分支的虚拟常量节点上填充D
}
换句话说,我正在创建一个表示图形的类型。节点可以是普通节点,也可以是虚拟节点、常量节点和非常量节点。一个图可以包含单个节点,也可以包含一个节点和一个图分支

当我创建一个函数
f
时,我希望它是常量中立的(在图中的一个节点的常量和非常量版本上执行相同的操作,但在分支图和非分支图上执行不同的操作)。我是否必须:

  • 复制代码
  • 使用
    std::启用\u如果
    hack

  • 代码的重复会复制错误,因此它不是最佳的
  • std::enable_如果在我的案例中生成错误消息

  • 是否有一种更智能的解决方案可以使
    f
    接受常量和非常量节点?

    只需使用类型模板参数,而不是使用模板参数和大量重载:

    template<class T> void f( Graph<T> ) { /*...*/ }
    
    模板空f(图){/*…*/}
    

    T
    将被推断为
    Node
    vNode
    const Node
    等。如果
    Node
    vs
    vNode
    很重要,则始终可以使用简单的trait类提取节点的类型。类似地,您可以将
    static\u assert
    与trait类一起使用,以确保
    T
    Node
    vNode

    的特化,为什么不简单地
    template void f(Graph)
    并让
    T
    得到适当的推导呢?您总是可以使用trait类轻松提取节点类型。为什么
    Graph
    Graph>相同的
    模板
    ,如果它们有不同的实现、接口,并且使用方式不同?还是有相同的功能处理它们?例如,您可以编写一个工厂模板,根据它是否为终端返回不同的类型。@Yakk:原因有二:1。
    是从
    分支
    派生的,分支是
    std::tuple
    包装器。由于
    std::tuple
    不是零大小,我认为空基优化不适用。2.有一些递归函数遍历
    图形
    ,在终端节点上终止它们需要函数重载。
    Graph
    的重载与
    Graph
    没有太大区别,后者产生的错误更短,意图更明确@TC:这是一个很好的主意,我支持它。谢谢你一如既往,这应该作为一个答案张贴。