C++泛型编程 CRTP 基类继承自派生类型提供的类

C++ generic programming CRTP base class inherit from class provided by derived type

本文关键字:类型 派生 泛型编程 CRTP 基类 继承 C++      更新时间:2023-10-16

浏览Stroustrup的"C++编程语言",第4版。27.4.1 组合数据结构中有一些我无法弄清楚的示例代码。使用派生类 (CRTP 模式) 通过模板参数提供的基类中的类型别名时会出现此问题。

 1 #include <vector>
 2 using namespace std;
 3 struct Red_black_balance {};
 4 template<typename N>
 5 struct Node_base : N::balance_type { //<==
 6     N* left_child;
 7     N* right_child;
 8     Node_base() { }
 9 };
10 template<typename Val, typename Balance>
11 struct Search_node : Node_base<Search_node<Val, Balance>>
12 {
13    using balance_type = Balance; // <==
14    Val val;
15    Search_node(Val v): val(v) {}
16 };
17 template<typename T>
18 using Rb_node = Search_node<T, Red_black_balance>; 
19 using My_node = Rb_node<double>;
20 int main(int, char **)
21 {
22    My_node my_root(0.0);
23    return 0;
24 }

下面是编译器输出(g++ 版本 4.9.2):

$ g++ -std=c++11 -Wall -pedantic -o test15 test15.cpp
test15.cpp: In instantiation of ‘struct Node_base<Search_node<double, Red_black_balance> >’:
test15.cpp:11:8:   required from ‘struct Search_node<double, Red_black_balance>’
test15.cpp:22:17:   required from here
test15.cpp:5:8: error: no type named ‘balance_type’ in ‘struct Search_node<double, Red_black_balance>’
 struct Node_base : N::balance_type {
        ^

据我了解,当模板实例化在main()中完成时,所有模板依赖类型都应根据该点的信息生成(与在模板定义点实例化的非依赖类型不同)。所以编译器在 main 中生成 Node_base 实例时应该知道 N::balance_type 对应于什么,对吧?但似乎并非如此。知道代码中出了什么问题吗?

这实际上是一个循环依赖问题。

template<typename N>
struct Node_base : N::balance_type

为了实例化Node_base<N>,我们需要先看看N::balance_type

template<typename Val, typename Balance>
struct Search_node : Node_base<Search_node<Val, Balance>>

为了实例化Search_node<Val, Balance>,我们需要先实例化Node_base<Search_node<Val, Balance>>。这需要实例化Search_node<Val, Balance>::balance_type,这需要实例化Search_node<Val, Balance>

您可以单独传递Balance

template <typename Derived, typename Balance>
struct Node_base : Balance { .. };
template <typename Val, typename Balance>
struct Search_node : Node_base<Search_node<Val, Balance>, Balance> { .. };