【问题标题】:C++: Template Parameter Cyclic DependencyC++:模板参数循环依赖
【发布时间】:2010-01-26 22:55:37
【问题描述】:

这更像是一个最佳实践问题,而不是一个语言问题,因为我已经有了一个可行的解决方案来解决 C++ 中常见的绊脚石。

我正在处理模板参数替换中的典型循环依赖问题。我有以下一对类:

template<class X>
class A { /* ... */ };

template<class X>
class B { /* ... */ };

我想将每一个实例化如下:

// Pseudocode -- not valid C++.
A<B> a;
B<A> b;

也就是说,我想将 A 绑定到 B,并将 B 绑定到 A。

我可以通过带有继承技巧的前向声明以粗略的方式解决问题:

class sA;
class sB;

class sA : public A<sB> { /* ... */ };
class sB : public B<sA> { /* ... */ };

但这带来了一系列问题,因为sAsB 确实不是AB。例如,如果不将A 的构造函数正确复制到sA 中,或者在代码周围以某种方式闪闪发光,我就无法调用它们。

我的问题是:处理这个问题的最佳实用方法是什么?这个问题有什么特别聪明的解决方案吗?

我同时使用 MSVC2008 和 G++,但欢迎使用具有编译器特定扩展的解决方案。

谢谢,

阿列克

【问题讨论】:

  • 我会对需要的实际示例感兴趣,在我看来,循环类型依赖首先不应该存在。
  • gf,假设A类是服务器类,B类是客户端类,两者都符合标准协议,这样可能会有一组其他客户端/服务器类可以连接一起。例如,B 从 A 查询数据,A 向 B 发送事件。它们每个都有一个指向另一个的指针(例如,A 包含一个 B*,B 包含一个 A*),它们通过调用每个上的预定义方法进行通信其他。这就是它的使用方式,尽管存在这个问题,它仍然运行良好。我希望这会使案件更清楚。也欢迎对上述设计提出建议。谢谢
  • 你需要重构。分解出通用的通信接口。
  • 其次,你应该至少在一侧打破类型依赖。

标签: c++ templates coding-style circular-dependency


【解决方案1】:

如前所述,解决此问题的最佳实用方法是重构 - 通过解耦来打破依赖关系。

可能的选项包括:

  • 使用虚方法的接口
  • 静态接口(可能使用类型特征或概念检查)
  • 在一侧或两侧使用回调(可能通过函子或信号缓和)

当您的需求突然发生变化时,这也会为您提供帮助。假设您在某些情况下需要一个特殊的server - 它当然应该支持您已经编写的所有客户端,您不想重写它们。或者在某些情况下您需要一些特殊的clients...
使用您的方法,这将需要重写双方,而解耦方法只需编写您需要更改的一方的修改版本。

例如与客户的静态方法:

template<class server>
class client {
    server& srv;
public:
    client(server& srv) : srv(srv) {};
    void work(const request& req) {
        srv.add_job(make_job(req));
    }
};

这里,client 甚至不需要知道 server 的具体类型 - 如果它没有成员函数 add_job(job&amp;) 或兼容的东西,编译就会失败。
如果您想更正式,可以查看静态断言和概念检查。

【讨论】:

    【解决方案2】:

    由于模板的类型命名了它的所有参数,你不能有一个无限循环的参数化。

    您可能(当然)只是试图同时向相反方向发送信息。这样做没有问题,但是您不能将信息封装在提供实现的类中。

    template< class W > // define an abstract class to pass data
    struct widget_traits {};
    
    template<>
    struct widget_traits< SpringySpring > { // specialize to put data in it
        struct properties { … };
        enum { boing = 3 };
    };
    
    template< class V >
    struct veeblfetzer_traits {};
    
    template<>
    struct veeblfetzer_traits< VonNeumann > {
        typedef int potrzebie;
    };
    
    template< struct WT, struct VT > // pass info by using as argument
    struct MyWidget { … };
    
    template< struct VT, struct WT > // both ways
    struct MyVeeblfetzer { … };
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-03-09
      • 2015-04-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-11-02
      • 1970-01-01
      相关资源
      最近更新 更多