Templates and nested classes/structures - c++

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.

Related

Use template parameter to pass both node type and data type for a linked list

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.

c++: I am using template to create an alias declaration and keep getting errors

I'm not too familiar with template and it's restrictions in C++. I'm creating a generic linked list using template and have a template alias as well. I keep getting error messages for the functions I created using the alias. My current code looks like this:
template <typename var>
struct Node
{
var value;
Node *next;
Node *prev;
};
template <typename var>
using nodepointer = Node<var>*;
void addNode(nodepointer &head, nodepointer &tail, var element);
The errors I get are:
error: variable or field 'addNode' declared void
void addNode(nodepointer &head, nodepointer &tail, var element);
error: missing template arguments before '&' token
void addNode(nodepointer &head, nodepointer &tail, var element);
Since nodepointer is a template, you need to make addNode() be its own template as well (which you need for its element parameter anyway) so that you can pass its template parameter to nodepointer's template parameter, eg:
template <typename var>
void addNode(nodepointer<var> &head, nodepointer<var> &tail, var element);
A single template can't be applied to multiple things like you are attempting, unless they are members of a class/struct and the template is applied to the entire class/struct as a whole, eg:
template <typename var>
struct List
{
struct Node
{
var value;
Node *next;
Node *prev;
};
using nodepointer = Node*;
void addNode(var element);
private:
nodepointer head, tail;
};

C++, error: invalid use of qualified-name

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.

How to use templates with Nested class in C++

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).

Good way to template a class/struct combination

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:
};
?