使用模板模板参数打破模板循环依赖关系

时间:2015-12-07 07:37:08

标签: c++ templates

如果我的理解是正确的,以下是模板类之间的经典循环依赖:

template <class MyB>
struct A {
    MyB *b_;
};

template <class MyA>
struct B {
    MyA *a_;
};

如果我们要使用AB B来实例化A,那么我们就不能从任何一个开始,因为我们必须写:{ {1}}(无限)。

我认为模板模板参数提供了一个解决方案。以下代码编译(使用A<B<A<B<...>>>版本4.8.2):

gcc

我是否错过了问题的本质?

更新:我刚刚进入this帖子,提出了基本相同的解决方案。

1 个答案:

答案 0 :(得分:2)

我会尝试设计我的代码以避免这些循环依赖。无论如何,如果有令人信服的理由提示,有几种方法可以解决这个问题:

  • 如您所述,使用模板模板参数可以通过打破循环来解决问题

    template <class MyB>
    struct A {
        MyB *b_;
    };
    
    template <template <class> class MyA>
    struct B {
        MyA<B> *a_;
    };
    
    int main() {
        using MyB = B<A>;
        using MyA = A<MyB>;
        MyA a;
        MyB b;
        a.b_ = &b; b.a_ = &a;
        return 0;
    }
    
  • 另一种解决方案可能是将您需要的类型封装到外部struct / class

    template<class Common> struct A
    {
      typedef typename Common::BT B;
      B* b;
    };
    
    template<class Common> struct B
    {
      typedef typename Common::AT A;
      A* a;
    };
    
    struct Common {
      using AT = A<Common>;
      using BT = B<Common>;
    };
    
    
    int main() {
      A<Common> a;
      B<Common> b;
      return 0;
    }
    
  • 根据代码的其余部分,在这样的简单情况下,您可能会使用可变参数模板

    template <class MyA>
    struct B;
    
    template <typename ...MyB>
    struct A {
      B<A<>> *b_;
    };
    
    template <>
    struct A<> {};
    
    template <class MyA>
    struct B {
      A<B<MyA>> *a_;
    };
    
    int main() {
    
      using BoA = B<A<>>;
      using AoBoA = A<B<A<>>>;
    
      BoA obj1;
      AoBoA obj2;
    
      obj1.a_ = &obj2;
      obj2.b_ = &obj1;
    
      return 0;
    }
    

最后值得注意的是,暴露一个共同的基类并使用类似CRTP的方法可能是实现这一目标的更简洁方法(你甚至可能获得清晰度和可读性的分数)