xan*_*xan 5 c++ diamond-problem
在Stroustrup的C++编程语言(第4版)中,第27.4.2节展示了一种"线性化"菱形类层次结构的技术,以避免虚拟基类的开销.他从一个真实项目(数据代码分析器工具)的钻石图案开始:

线性版本绘制为:

和

代码大纲是:
namespace ipr {
struct Node { ... };
struct Expr : Node { ... };
struct Stmt : Expr { ... };
struct Decl : Stmt { ... };
struct Var : Decl { ... };
namespace impl {
template<class T> struct Node : T { ... };
template<class T> struct Expr : Node<T> { ... };
template<class S> struct Stmt : S { ... };
template<class D> struct Decl : Stmt<Expr<D>> { ... };
struct Var : Decl<ipr::Var> { ... };
}
}
Run Code Online (Sandbox Code Playgroud)
我对不规则结构感到困惑.基于最初的描述,我期待impl看起来像:
namespace impl {
template<class T> struct Node : T { ... };
template<class T> struct Expr : Node<T> { ... };
template<class S> struct Stmt : Expr<S> { ... };
template<class D> struct Decl : Stmt<D> { ... };
struct Var : Decl<ipr::Var> { ... };
}
Run Code Online (Sandbox Code Playgroud)
而且我在想这些类的完整图表是:

我的问题是,为什么"内部"三个impl模板类没有并行形式,就像我的代码版本一样?
我最好的猜测来自于查看实际的 Pivot 代码,其中包含
template<class D> struct Decl : Stmt<Node<D>> { ... };
Run Code Online (Sandbox Code Playgroud)
而不是斯特鲁斯特鲁普的
template<class D> struct Decl : Stmt<Expr<D>> { ... };
Run Code Online (Sandbox Code Playgroud)
这表明毕竟impl::Stmt不一定源自impl::Expr,如原始菱形图所示(尽管它仍然源自接口ipr::Expr)。它不是从impl::ExprforDecl和派生的Var,但它适用于其他实现类,例如impl::For:
struct For : Stmt<Expr<ipr::For> > { ... }
Run Code Online (Sandbox Code Playgroud)
我不知道为什么斯特鲁斯特鲁普没有解释这种不规则现象。也许他认为他通过更改为Stmt<Node>来删除它Stmt<Expr>,或者也许他根本没有更改它(也就是说,代码在他复制后发生了更改)并且他想保持原样而不解释每个细节。
希望有更好的答案能够解释它。