1.I did something as below:
template <class T>
class RBTree{
public:
struct TreeNode{
T data;
bool color;
TreeNode* left;
TreeNode* right;
TreeNode* parent;
static TreeNode* NIL;
TreeNode(T data, TreeNode* parent, TreeNode* left = NIL, TreeNode* right = NIL)
:data(data), color(RED), left(left), right(right), parent(parent){}
}
TreeNode* TreeNode::NIL = new TreeNode(-1, nullptr);
};
And it throws me an error...
[Error] invalid use of qualified-name 'RBTree<T, Comp>::TreeNode::NIL'
I really don't know why... after I made it outside of the whole class RBTree, as blow, it works...
template <class T>
class RBTree{
...
};
template <class T>
typename RBTree<T>::TreeNode* RBTree<T>::TreeNode::NIL = new TreeNode(-1, nullptr);
But I don't know why I got an error at the first time?
I think the grammar may be correct...
2.Soon I made my class as below.
//in RBTree.hpp
template <class T>
class RBTree{
public:
... //the same as above
private:
TreeNode* root;
};
template <class T>
typename RBTree<T>::TreeNode* RBTree<T>::TreeNode::NIL = new TreeNode(-1, nullptr);
//in RBTree_IMPL.hpp
template <class T>
void RBTree<T>::insert(const T & data){
if(root == nullptr){
root = new TreeNode(data, nullptr);
...
}
...
}
//in RBTree_test.cpp
int main(){
RBTree<int> rb;
rb.insert(3);
}
I got lots of errors like
[Error] recursive evaluation of default argument for 'RBTree<T>::TreeNode::TreeNode(T, RBTree<T>::TreeNode*, RBTree<T>::TreeNode*, RBTree<T>::TreeNode*) [with T = int]'
maybe about the constructor of the inner class TreeNode. The error happens when I use the RBTree::insert() in main() to create the 'root' node.
I don't know why. It maybe very interesting to probe the static member. And thank you for reading my question. Due to the fact that in 90 mins can only ask one question, so I write two questions in it.. Thx!
static data members must be defined at namespace scope. You were attempting to define it at class scope.
As for the second error, you have an infinite recursion. You are trying to define what the value of NIL is, but since you aren't providing all the arguments, the default arguments are being used, which means you are effectively declaring
template <class T>
typename RBTree<T>::TreeNode* RBTree<T>::TreeNode::NIL =
new TreeNode(-1, nullptr,NIL,NIL);
Maybe you intended for the default arguments to be nullptr instead.
Related
In my linked list class I want to pass the dataType of the data to store as a template parameter as well as the node type that contains the data, but I keep getting compile error.
Heres the node class
llist.h
template<class itemType>
class Node {
itemType item{};
Node* next{};
Node* prev{};
public:
Node* getnext() { return next; }
Node* getprev() { return prev; }
itemType getitem() { return item; }
};
and heres the linkedlist class.
llist.h
template <class itemType, class nodeType>
class LinkedList
{
//I am trying to say
//using node=Node<itemType>
//but dont want to use Node directly and want to get the type of Node from template argument
using node = nodeType<itemType>; node* head{};
public:
node* getHead() { return head; }
};
When I try to instantiate it from main(), I get compiler errors
int main()
{
std::cout << "Hello World!\n";
LinkedList<int, Node<int> > list;
list.getHead();
}
Here are the errors:
1>X:\code1\Blib\Blib\llist.h(16,23): error C2143: syntax error: missing ';' before '<'
1>C:\code\Blib\Blib\llist.h(21): message : see reference to class template instantiation 'LinkedList<itemType,nodeType>' being compiled
1>C:\code\Blib\Blib\llist.h(16,1): error C2059: syntax error: '<'
1>C:\code\Blib\Blib\llist.h(16,1): error C2238: unexpected token(s) preceding ';'
1>Done building project "Blib.vcxproj" -- FAILED.
If you want to use nodeType as template like nodeType<itemType>, you can declare it as template template parameter.
template <class itemType, template <typename> class nodeType>
class LinkedList
Then use it like
LinkedList<int, Node> list;
LIVE
If you want to declare it as type template parameter as you're doing now, then just use it as
template <class itemType, class nodeType>
class LinkedList
{
using node = nodeType;
...
};
LIVE
Template template parameter approach becomes problematic if you have different node types and some of them have additional template parameters. You can also go another way and extract itemType type from Node instead of passing it to LinkedList explicitly. This can be done with decltype applied to a member function of Node:
template<class nodeType>
class LinkedList {
using itemType = std::decay_t<decltype(std::declval<nodeType>().getItem())>;
// ...
};
Here std::decay_t is used to remove a possible reference from the return type of getItem(). In your particular example it returns itemType, but in general I would expect [const] itemType&.
Alternatively, we can just use a member type in Node:
template<class itemType>
class Node {
public:
using type = itemType;
};
template<class nodeType>
class LinkedList {
using itemType = typename nodeType::type;
// ...
};
Now can write LinkedList<Node<int>> and get itemType equal to int.
This question already has an answer here:
Nested templates with dependent scope
(1 answer)
Closed 6 years ago.
having trouble when trying to compile a template class.
In the .h file
template <typename dataType>
class Node {
private:
dataType nodeData;
Node<dataType>* nextLink;
Node<dataType>* previousLink;
public:
Node(const dataType& nodeData);
// methods
In the .template file
template <typename dataType>
Node<dataType>::dataType Node<dataType>::getData() const {
return nodeData;
};
The error I get when trying to compile is:
need ‘typename’ before ‘Node<dataType>::dataType’ because ‘Node<dataType>’ is a dependent scope
Node<dataType>::dataType Node<dataType>::getData() const {
So then I add typename and it then gives me this error:
error: expected nested-name-specifier before ‘dataType’
typename dataType getData() const;
^
error: expected ‘;’ at end of member declaration
error: declaration of ‘int Node<dataType>::dataType’
error: shadows template parm ‘class dataType’
template <typename dataType>
^
What have I done wrong?
There is no member called dataType, I assume the return type should be just the template dataType:
template <typename dataType>
dataType Node<dataType>::getData() const {
return nodeData;
}
The compiler message is misleading in this case as it doesn't find proper definition, it assumes the dataType refers to the template argument.
template <typename DataType>
class Node {
public:
using dataType = DataType;
private:
dataType nodeData;
Node<dataType>* nextLink;
Node<dataType>* previousLink;
public:
Node(const dataType& nodeData);
dataType getData() const;
};
template <typename DataType>
typename Node<DataType>::dataType Node<DataType>::getData() const {
return nodeData;
};
specfy typename like this.
http://melpon.org/wandbox/permlink/Agu2s6vw6OLfbbRh
The presented example code is incomplete, so one would have to guess at the concrete problem.
However, here's how to do that class in a practical way, without problems like the one you're encountering:
template< class Item >
struct Node
{
Node* next;
Node* prev;
Item item;
};
Showing that it's sometimes possible to solve a problem without knowing the exact details.
I am trying to use templates for a nested class. I am not sure how to access the class type of the inner class from another class.
Sample Code below.
// I have a List class that can accept any type. It has an inner class
template <class T>
class List
{
public:
class Node
{
public:
T data;
Node* next;
Node* prev;
};
void addElement(Node& value);
private:
Node* head;
};
// Here I am making an array of Lists
template <class T>
class ListArray
{
public:
// Here is my question.
void add(Node& value); // How to give "Node" class type here ?
private:
List<T> _listArr[10];
};
// Is the below the right way to define ListArray::add, especially the way in which Node type can be passed to it ?
template <class T>
void ListArray<T>::add(List<T>::Node& value)
{
// Make a call to List::addElement and pass Node& value
_listArr[0].addElement(value);
//....
}
Could you kindly let me know how the above can be achieved ? Thanks.
Node is a nested type of a class template:
template <class T>
class ListArray
{
public:
typedef typename List<T>::Node Node_type;
void add(Node_type& value); // Refer to it as Node_type
private:
List<T> _listArr[10];
};
And:
template <class T>
void ListArray<T>::add(typename ListArray<T>::Node_type& value)
{
_listArr[0].addElement(value);
//....
}
I used typedef to define local name for node type. It is very useful - now, clients of ListArray can write code, that uses Node_type explicitly (without knowing what it actually is). This technique is used heavily in std library - usually, std:: types have tons of typedefs to allow writing flexible code.
Also, note the typename keyword - it is required in case of nested types of class templates. It indicates, that given name is the name of a type (without it, you should get a compiler error).
what's the most effective way to template a class that calls will need to call a templated struct. This is the classic ordered list problem with templating. My entire ordered list works as of now (when I simply change the types manually). However, I am not sure how to go about templating the pair of objects (the struct and the class).
So basically, here is how my code is structured:
struct Node {
int* data;
Node* next;
};
class OList {
private:
Node* start;
int size;
public:
a bunch of manipulation functions
};
So, my desire is to simply template the struct, and then accept a parameter that will pass the template into the Node struct type. However, my first attempt, which was to do:
template<class T>
before the Node struct and change all the ints* to T* failed miserably. What might be a better approach in anybody's experience? Can anybody point me in the right direction or give me some good references for template basics? All I can find are specific questions, which doesn't give me a good background to how templating works.
UPDATE: My code works very well at this point. The only thing I still do not understand is how to return pointers of the Node struct in functions. For example, in a function that might be,
template <class T>
List<T>::Node<T>* List<T>pos(int val); //trying to return a pointer to the node at a specified spot
I get the following error: "Non-templated 'Node' used as template. note: use OList::template Node' to indicate that it is a template (???) error: need 'typename' before 'OList::Node' because 'OList is a dependent scope" What is the most efficient way to clear up these errors? Code works perfectly when this one function is commented out.
template <typename T> // <----
struct Node {
T* data; // <----
Node* next;
};
template <typename T> // <----
class OList {
private:
Node<T>* start; // <----
int size;
public:
a bunch of manipulation functions
};
Alternatively...
template <typename T>
class OList {
private:
typedef ::Node<T> Node; // <---- just do it once
Node* start;
...or as suggested in BWG's comment, define Node directly in OList, so all the <T> aspect is implicit...
template <typename T>
class OList {
private:
struct Node { T* data; int size; }; // <----
Node* start;
Example of out-of-line member function definition:
template <typename T>
class OList
{
private:
struct Node { T* data; };
Node* f(Node*);
public:
};
template <typename T>
typename OList<T>::Node* OList<T>::f(typename OList<T>::Node* p) // see notes
{
Node* p2 = p; // can use Node as if inside class definition
return p2;
}
Note the ugly line...
typename OList<T>::Node* OList<T>::f(typename OList<T>::Node* p)
...where typename is needed to indicate that Node names a type inside QList<T> (so it can do a bit more to make sure the function might makes sense even before it's instantiated for any specific type 'T'), and we need to continually mention both that Node's inside QList's scope, and that the specific instantiation of QList in which it's to be found is based on the template parameter T. It all makes sense, but it's a bit pedantic.
As for how templates work in general, that's arguably "too broad" for answers on Stack Overflow, but FWIW perhaps the fastest way to jump-start some practical understanding of that (which will need some refinement afterwards), is by comparing them to macros. Consider:
#define NODE(T) \
struct Node ## T { \
T* data; \
Node ## T* next; \
};
With this, you can say NODE(int) or NODE(float) to generate Node_int and Node_float structures for those types. With templates, you don't (normally) need to define each specialisation separately - it's done implicitly when used ("parametric polymorphism")- so just start using them for variables ala Node<int> my_node_for_ints.
Do you mean something like:
template <typename T>
struct Node {
T data;
Node* next;
};
template <typename T>
class OList {
private:
Node<T> start;
int size;
public:
};
?
I have a simple container :
template <class nodeType> list {
public:
struct node {
nodeType info;
node* next;
};
//...
};
Now, there is a function called _search which searches the list and returns a reference to the node which matched. Now, when I am referring to the return-type of the function, I think it should be list<nodeType>::node*. Is this right? When I define the function inline, it works perfectly:
template <class nodeType> list {
public:
struct node {
nodeType info;
node* next;
};
node* _search {
node* temp;
// search for the node
return temp;
}
};
But, if I define the function outside the class,
template <class nodeType> list<nodeType>::node* list<nodeType>::_search() {
//function
}
it doesn't work. The compiler gives an error saying Expected constructor before list<nodeType>::_search or something. The error is something similar to this. I don't have a machine on which I can test it currently.
Any help is sincerely appreciated.
that's because node is a dependent type. You need to write the signature as follows (note that I have broken it into 2 lines for clarity)
template <class nodeType>
typename list<nodeType>::node* list<nodeType>::_search()
{
//function
}
Note the use of the typename keyword.
You need to tell the compiler that node is a type using the keyword typename.Otherwise it will think node as a static variable in class list. Add typename whenever you use node as a type in your implementation of list.