0

这本身就是一个最佳实践问题,而不是一个语言问题,因为我已经有了一个可行的解决方案来解决似乎是 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中,或者在代码周围以某种方式闪闪发光的类型转换,我就无法调用 's 构造函数。

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

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

谢谢,

阿列克

4

2 回答 2

2

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

可能的选项包括:

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

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

例如,与客户采用静态方法:

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&)或兼容的东西,编译就会失败。
如果您想更正式,可以查看静态断言和概念检查。

于 2010-01-26T23:52:46.420 回答
0

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

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

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 { … };
于 2010-01-26T23:48:07.227 回答