拆分模板 class 嵌套模板的定义和声明失败
Splitting template class definitions and declarations fails for nested templates
我知道我想要什么,但我不知道如何告诉编译器我想要什么。我在 .h 和 .cpp 文件中拆分了声明和方法定义,但是 .cpp 文件包含在 header 中,所以我所做的只是单独的声明和定义。
header 文件 (avltree.h) - 它包含源文件!:
template < class KEY_T, class DATA_T >
class CAvlTree {
public:
//----------------------------------------
template < class KEY_T, class DATA_T >
class CNode;
typedef CNode< KEY_T, DATA_T> * tNodePtr;
template < class KEY_T, class DATA_T >
class CNode {
public:
KEY_T key;
DATA_T data;
CNode< KEY_T, DATA_T > * left;
CNode< KEY_T, DATA_T > * right;
char balance;
CNode() : left(nullptr), right(nullptr), balance(0) {}
CNode(KEY_T key, DATA_T data) :
key (key), data (data), left(nullptr), right(nullptr), balance(0) {}
};
//----------------------------------------
template < class KEY_T, class DATA_T >
struct tAvlInfo {
CNode< KEY_T, DATA_T> * root;
CNode< KEY_T, DATA_T> * current;
KEY_T key;
bool isDuplicate;
bool branchChanged;
};
typedef bool (* tNodeProcessor) (CNode< KEY_T, DATA_T> * nodePtr);
private:
tAvlInfo< KEY_T, DATA_T > m_info;
//----------------------------------------
public:
DATA_T* Find(KEY_T& key);
private:
CNode< KEY_T, DATA_T> * AllocNode(void);
};
#include "avltree.cpp"
源文件(avltree.cpp):
template < typename KEY_T, typename DATA_T >
DATA_T* CAvlTree< KEY_T, DATA_T >::Find (KEY_T& key)
E0276 name followed by '::' must be a class or namespace name
{
CNode* root;
for (CNode* node = m_info.root; node; ) {
if (key < node->key)
node = node->left;
else if (key > root->key)
node = node->right;
else {
m_info.current = node;
return &node->data;
}
}
return nullptr;
}
template < typename KEY_T, typename DATA_T >
CNode* CAvlTree< KEY_T, DATA_T >::AllocNode (void)
E0020 identifier "CNode" is undefined
E0864 CAvlTree is not a template
{
if (m_info.current = new CNode < KEY_T, DATA_T >) {
m_info.branchChanged = true;
return m_info.current;
}
return nullptr;
}
编译器所说的(VS 2019 社区,启用 c++2020):
E0276 name followed by '::' must be a class or namespace name
E0020 identifier "CNode" is undefined
E0864 CAvlTree is not a template
我不知道如何以正确的方式写下来。请赐教。
我有一个模板的类似代码 class,它具有一个有效的类型名称,但无法从中得出如何对两个类型名称执行此操作的结论。
在我的源代码中使用 tNodePtr 类型而不是 CNode< KEY_T, DATA_T > * 也不起作用。
顺便说一句,我知道编译器不会仅仅因为我使用相同的名称就从 CAvlTree 声明中“转移”KEY_T 和 DATA_T。
你的问题是:
template < class KEY_T, class DATA_T >
class CNode;
那些KEY_T
和DATA_T
与CAvlTree
中的一个无关。
clang 和 gcc 甚至会因为名称阴影而为那些发出错误(我不知道 VS 是否也这样做)。
由于 CNode
是一个 class 模板,编译器希望您在所有使用 [= 的地方为其提供模板参数(就像您为 CNode< KEY_T, DATA_T> * AllocNode(void);
所做的那样) 16=].
但是如果你在代码中对每个 CNode
使用 KEY_T
和 CAvlTree
的 DATA_T
,那么问题是你为什么要定义 CNode
首先作为 class 模板。
这部分代码表示您不希望 CNode
成为 class 模板:
template < class KEY_T, class DATA_T >
class CNode;
typedef CNode< KEY_T, DATA_T> * tNodePtr;
// …
CNode< KEY_T, DATA_T> * AllocNode(void);
template < class KEY_T, class DATA_T > struct tAvlInfo
似乎也是如此。
因此,我认为您想要的代码应该如下所示:
template <class KEY_T, class DATA_T>
class CAvlTree {
public:
//----------------------------------------
class CNode {
public:
KEY_T key;
DATA_T data;
CNode *left;
CNode *right;
char balance;
CNode() : left(nullptr), right(nullptr), balance(0) {}
CNode(KEY_T key, DATA_T data)
: key(key), data(data), left(nullptr), right(nullptr), balance(0) {}
};
//----------------------------------------
struct tAvlInfo {
CNode *root;
CNode *current;
KEY_T key;
bool isDuplicate;
bool branchChanged;
};
typedef bool (*tNodeProcessor)(CNode *nodePtr);
private:
tAvlInfo m_info;
//----------------------------------------
public:
DATA_T *Find(KEY_T &key);
private:
CNode *AllocNode(void);
};
template <typename KEY_T, typename DATA_T>
DATA_T *CAvlTree<KEY_T, DATA_T>::Find(KEY_T &key) {
CNode *root;
for (CNode *node = m_info.root; node;) {
if (key < node->key)
node = node->left;
else if (key > root->key)
node = node->right;
else {
m_info.current = node;
return &node->data;
}
}
return nullptr;
}
template <typename KEY_T, typename DATA_T>
auto CAvlTree<KEY_T, DATA_T>::AllocNode(void) -> CNode * {
if (m_info.current = new CNode) {
m_info.branchChanged = true;
return m_info.current;
}
return nullptr;
}
并且使用 auto identifier ( argument-declarations... ) -> return_type
语法允许您直接使用 CName
名称。否则,您需要编写 template <typename KEY_T, typename DATA_T> typename CAvlTree<KEY_T, DATA_T>::CNode* CAvlTree<KEY_T, DATA_T>::AllocNode(void)
我知道我想要什么,但我不知道如何告诉编译器我想要什么。我在 .h 和 .cpp 文件中拆分了声明和方法定义,但是 .cpp 文件包含在 header 中,所以我所做的只是单独的声明和定义。
header 文件 (avltree.h) - 它包含源文件!:
template < class KEY_T, class DATA_T >
class CAvlTree {
public:
//----------------------------------------
template < class KEY_T, class DATA_T >
class CNode;
typedef CNode< KEY_T, DATA_T> * tNodePtr;
template < class KEY_T, class DATA_T >
class CNode {
public:
KEY_T key;
DATA_T data;
CNode< KEY_T, DATA_T > * left;
CNode< KEY_T, DATA_T > * right;
char balance;
CNode() : left(nullptr), right(nullptr), balance(0) {}
CNode(KEY_T key, DATA_T data) :
key (key), data (data), left(nullptr), right(nullptr), balance(0) {}
};
//----------------------------------------
template < class KEY_T, class DATA_T >
struct tAvlInfo {
CNode< KEY_T, DATA_T> * root;
CNode< KEY_T, DATA_T> * current;
KEY_T key;
bool isDuplicate;
bool branchChanged;
};
typedef bool (* tNodeProcessor) (CNode< KEY_T, DATA_T> * nodePtr);
private:
tAvlInfo< KEY_T, DATA_T > m_info;
//----------------------------------------
public:
DATA_T* Find(KEY_T& key);
private:
CNode< KEY_T, DATA_T> * AllocNode(void);
};
#include "avltree.cpp"
源文件(avltree.cpp):
template < typename KEY_T, typename DATA_T >
DATA_T* CAvlTree< KEY_T, DATA_T >::Find (KEY_T& key)
E0276 name followed by '::' must be a class or namespace name
{
CNode* root;
for (CNode* node = m_info.root; node; ) {
if (key < node->key)
node = node->left;
else if (key > root->key)
node = node->right;
else {
m_info.current = node;
return &node->data;
}
}
return nullptr;
}
template < typename KEY_T, typename DATA_T >
CNode* CAvlTree< KEY_T, DATA_T >::AllocNode (void)
E0020 identifier "CNode" is undefined
E0864 CAvlTree is not a template
{
if (m_info.current = new CNode < KEY_T, DATA_T >) {
m_info.branchChanged = true;
return m_info.current;
}
return nullptr;
}
编译器所说的(VS 2019 社区,启用 c++2020):
E0276 name followed by '::' must be a class or namespace name
E0020 identifier "CNode" is undefined
E0864 CAvlTree is not a template
我不知道如何以正确的方式写下来。请赐教。
我有一个模板的类似代码 class,它具有一个有效的类型名称,但无法从中得出如何对两个类型名称执行此操作的结论。
在我的源代码中使用 tNodePtr 类型而不是 CNode< KEY_T, DATA_T > * 也不起作用。
顺便说一句,我知道编译器不会仅仅因为我使用相同的名称就从 CAvlTree 声明中“转移”KEY_T 和 DATA_T。
你的问题是:
template < class KEY_T, class DATA_T >
class CNode;
那些KEY_T
和DATA_T
与CAvlTree
中的一个无关。
clang 和 gcc 甚至会因为名称阴影而为那些发出错误(我不知道 VS 是否也这样做)。
由于 CNode
是一个 class 模板,编译器希望您在所有使用 [= 的地方为其提供模板参数(就像您为 CNode< KEY_T, DATA_T> * AllocNode(void);
所做的那样) 16=].
但是如果你在代码中对每个 CNode
使用 KEY_T
和 CAvlTree
的 DATA_T
,那么问题是你为什么要定义 CNode
首先作为 class 模板。
这部分代码表示您不希望 CNode
成为 class 模板:
template < class KEY_T, class DATA_T >
class CNode;
typedef CNode< KEY_T, DATA_T> * tNodePtr;
// …
CNode< KEY_T, DATA_T> * AllocNode(void);
template < class KEY_T, class DATA_T > struct tAvlInfo
似乎也是如此。
因此,我认为您想要的代码应该如下所示:
template <class KEY_T, class DATA_T>
class CAvlTree {
public:
//----------------------------------------
class CNode {
public:
KEY_T key;
DATA_T data;
CNode *left;
CNode *right;
char balance;
CNode() : left(nullptr), right(nullptr), balance(0) {}
CNode(KEY_T key, DATA_T data)
: key(key), data(data), left(nullptr), right(nullptr), balance(0) {}
};
//----------------------------------------
struct tAvlInfo {
CNode *root;
CNode *current;
KEY_T key;
bool isDuplicate;
bool branchChanged;
};
typedef bool (*tNodeProcessor)(CNode *nodePtr);
private:
tAvlInfo m_info;
//----------------------------------------
public:
DATA_T *Find(KEY_T &key);
private:
CNode *AllocNode(void);
};
template <typename KEY_T, typename DATA_T>
DATA_T *CAvlTree<KEY_T, DATA_T>::Find(KEY_T &key) {
CNode *root;
for (CNode *node = m_info.root; node;) {
if (key < node->key)
node = node->left;
else if (key > root->key)
node = node->right;
else {
m_info.current = node;
return &node->data;
}
}
return nullptr;
}
template <typename KEY_T, typename DATA_T>
auto CAvlTree<KEY_T, DATA_T>::AllocNode(void) -> CNode * {
if (m_info.current = new CNode) {
m_info.branchChanged = true;
return m_info.current;
}
return nullptr;
}
并且使用 auto identifier ( argument-declarations... ) -> return_type
语法允许您直接使用 CName
名称。否则,您需要编写 template <typename KEY_T, typename DATA_T> typename CAvlTree<KEY_T, DATA_T>::CNode* CAvlTree<KEY_T, DATA_T>::AllocNode(void)