这本身就是一个最佳实践问题,而不是一个语言问题,因为我已经有了解决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> { /* ... */ };
但是这会带来一系列问题,因为sA
和sB
确实不是A
和B
。例如,我无法调用A
的构造函数而没有将它们正确地复制到sA
中,或者以某种方式在代码周围闪烁出来。
我的问题是:处理这个问题的最佳实用方法是什么?这个问题有什么特别聪明的解决方案吗?
我正在使用MSVC2008和G ++,但欢迎使用具有编译器特定扩展名的解决方案。
谢谢,
阿列克
答案 0 :(得分:2)
如上所述,处理此问题的最佳实用方法是重构 - 通过解耦来打破依赖关系。
可能的选项包括:
只要您的要求突然改变,这也可以帮助您。假设在某些情况下你需要一个特殊的server
- 它当然应该支持你已经写过的所有客户端,你不想重写它们。或者在某些情况下你需要一些特殊的client
......
使用你的方法,这需要重写双方,只需要一个解耦的方法,只需要编写你需要改变的方面的修改版本。
以此为例与客户的静态方法:
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&)
或兼容的东西,编译就会失败。
如果你想要更正式,你可以查看静态断言和概念检查。
答案 1 :(得分: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 { … };