I have a class something like that:
template <class T>
class bag
{
public:
private:
typedef struct{void* prev; struct{T item; unsigned int count;} body; void* next;}* node;
typedef struct{
node operator->() { return current; }
operator(){;} // <- i can not do that, right?
private:
node current;
} iterator;
//...
};
So, how to write a constructor for the bag::iterator?
Make some nice name for it :-)
typedef struct NoName1 {void* prev; NoName1(){}; struct NoName2{T item; unsigned int count; NoName2() {}} body; void* next;}* node;
EDIT: LOL sorry, wrote it for the wrong one, but the principle is the same :-)
There is no way to write a constructor for bag::iterator because iterator is a typedef name, which are prohibited from being used as constructor names:
14882:2003 12.1/3
a typedef-name that names a class shall not be used as the identifier in the declarator for a constructor declaration.
There is even an example in the standard, although in a different paragraph, 7.1.3/5:
typedef struct {
S(); //error: requires a return type because S is
// an ordinary member function, not a constructor
} S;
You will have to give that struct a name, if you want a user-defined constructor. The typedef struct { } name; style of programming is usually discouraged by C++ style guides anyway, in favor of struct name { };.
Related
struct Element{
Element() {}
int data = NULL;
struct Element* right, *left;
};
or
struct Element{
Element() {}
int data = NULL;
Element* right, *left;
};
I was working with binary trees and I was looking up on an example. In the example, Element* right was struct Element* right. What are the differences between these and which one would be better for writing data structures?
I was looking up from this website:
https://www.geeksforgeeks.org/binary-tree-set-1-introduction/
In C, struct keyword must be used for declaring structure variables, but it is optional(in most cases) in C++.
Consider the following examples:
struct Foo
{
int data;
Foo* temp; // Error in C, struct must be there. Works in C++
};
int main()
{
Foo a; // Error in C, struct must be there. Works in C++
return 0;
}
Example 2
struct Foo
{
int data;
struct Foo* temp; // Works in both C and C++
};
int main()
{
struct Foo a; // Works in both C and C++
return 0;
}
In the above examples, temp is a data member that is a pointer to non-const Foo.
Additionally, i would recommend using some good C++ book to learn C++.
In C++, defining a class also defines a type with the same name so using struct Element or just Element means the same thing.
// The typedef below is not needed in C++ but in C to not have to use "struct Element":
typedef struct Element Element;
struct Element {
Element* prev;
Element* next;
};
You rarely have to use struct Element (other than in the definition) in C++.
There is however one situation where you do need it and that is when you need to disambiguate between a type and a function with the same name:
struct Element {};
void Element() {}
int main() {
Element x; // error, "struct Element" needed
}
Why is this invalid?
typedef struct _NODE_struct_
{
int value;
std::vector<node_t*> neighbors;
} node_t;
When this is valid:
struct node_t
{
int value;
std::vector<node_t*> neighbors;
};
The first gives error: 'node_t' was not declared in this scope. All my main function does is declare an object n of type node_t. It does not instantiate or manipulate.
The correct way to express what you're trying to say is to typedef a forward declaration.
typedef struct _NODE_struct_ node_t;
struct _NODE_struct_
{
int value;
std::vector<node_t*> neighbors;
};
But (especially since this is C++, not C) it would be better to not even use the typedef:
struct node_t;
struct node_t
{
int value;
std::vector<node_t*> neighbors;
};
(and even in C you could write struct node_t*)
but at this point, it becomes obvious that you don't even need the forward declaration. Also, all names that end in '_t' are reserved, so:
struct Node
{
int value;
std::vector<Node*> neighbors;
};
(ordinarily I would give the spiel about avoiding pointers in containers, but it looks like the nodes are borrowed peers, so it is correct)
The first code bit is trying to combine a definition with a typedef before it happens. If you are coming from a scripting or function context where you are trying to map an anon class, this does not work for C++. (I realize the comments answer the question, I thought I'd write this answer anyway just for reference.)
typedef struct {
int Key_value;
Node *link;
}Node;
Is the above declaration valid? or should I use
typedef struct _node{
int Key_value;
_node *link;
}Node;
No, it's not valid (as you would have noticed if you tried to compile it).
The typedef alias isn't introduced until the after the typedef, so you can't use it inside itself.
The second one isn't valid either (in C), _node is not a valid type name. You must use struct _node for the self-reference.
I tend to use pre-declaration and split it:
typedef struct Node Node;
struct Node {
int Key_Value;
Node *link;
};
The thing is that you can actually give the same name to both the structure and the typedef:
typedef struct Node {
int Key_value;
struct Node *link;
} Node;
Here I have added something which would have caused your code to not compile in a C compiler: The typedef isn't created until after the structure is defined. This means we must use the structure name in the link member declaration.
This can either be solved by giving the structure a name, as above, or by declaring the typedef first:
typedef struct Node *Node;
struct Node {
int Key_value;
Node *link;
};
Also note that in C++ you don't need to use the typedef keyword, or the struct keyword when declaring the link member:
// C++ version
struct Node {
int Key_value;
Node *link;
};
Structure (and class) names can be used as types in C++.
The first declaration is invalid, because Node is not known when you declare link as a structure member. The reason is that a declaration name is visible only after the declarator (simply put, that is after a comma, equal sign, or semi-colon). So, typedef being a declaration like any other, the name Node is only visible after the final semi-colon that ends the declaration statement.
Thus, you must use the second form (the first won't even compile). However, if you're on C, note that you should prepend the struct keyword to _node, like this:
typedef struct _node {
int Key_value;
struct _node *link;
} Node;
This is not necessary if you're on C++.
Both are invalid. Here's one valid way, for C and C++:
struct Node
{
int Key_value;
struct Node *link;
};
// if C, you can also do this
typedef struct Node Node;
The main point is that whatever the type of Link is, it must be something that's already been declared. The line struct X { .... declares that struct X is a type (but does not define it yet, but that's OK).
In C you should do:
typedef struct _node {
int Key_value;
struct _node *link;
} Node;
However, if you are using C++, it's simpler to omit the typedef at all:
struct Node {
int Key_Value;
Node* link;
}
As an example, consider a simple data structure like a linked list. In C, it might look like:
struct Node
{
struct Node *next;
void *data;
};
void *getLastItem(struct Node*);
...
I'd like to have the same struct and functions, but with better type checking by declaring the type of the data field, which will always be a pointer to something. An example use:
Node<Thing*> list = getListOfThings();
Thing *t = list->data;
t = getLastItem(list);
...
But I don't want to generate an implementation for every type of pointer, as happens with a normal template. In other words, I want something more like a generic or parametric type from Java, ML, and other languages. I just tried the code below as a test. The untyped C-like part would eventually go in a implementation file, while the template and function declarations would be in the header file. I'm assuming they would be optimized away and I'd be left with machine code that is about the same as the C version, except it would be type-checked.
But I'm not great with C++... Is there a way to improve this, or use more idiomatic C++, perhaps template specialization?
#include <stdio.h>
struct NodeImpl
{
NodeImpl *next;
void *data;
};
void *getLastItemImpl(NodeImpl *list)
{
printf("getLastItem, non-template implementation.\n");
return 0; // not implemented yet
}
template <typename T>
struct Node
{
Node<T> *next;
T data;
};
template <typename T>
T getLastItem(Node<T> *list)
{
return (T)getLastItemImpl((NodeImpl*)list);
}
struct A { };
struct B { };
int main()
{
Node<A*> *as = new Node<A*>;
A *a = getLastItem(as);
Node<B*> *bs = new Node<B*>;
B *b = getLastItem(bs);
}
This is exactly what Boost.PointerContainer does, check its implementation. Basically what it does is implement the specialization for void*, and have any other implementation forward to it static_casting the parameters in and out.
struct Node
{
struct Node *next;
void *data;
};
void *getLastItem(struct Node*);
...
This is common for C, but not for C++. In C++ it usually looks like this:
template<typename T>
struct Node
{
struct Node *next;
T data;
};
T& getLastItem(const Node&);
...
Note the important difference -- the C version has another level of indirection in order to share implementations, while the C++ version need not do this. This means the C version has another n dynamic memory allocations, where n is the number of items in the list. Given that each allocation usually requires obtaining a global lock, often has at least 16 bytes of overhead per allocation, as well as all the overhead the memory manager brings to the party, the advantage of the C++ version is not insignificant, particularly when you include things like cache locality in the considerations.
Put another way, for Node<int>, the C++ version stores an int, while the C version stores an int *, along with a dynamic allocation for the int.
This of course discounting that a linked list is a horrendous data structure 90% of the time.
If you must use a linked list, and if you must use dynamic allocation for the data members, then your idea of "replace the pointers with void*s" is not unreasonable. However, if you have access to a C++11 compiler (VS2010, recent GCC versions, etc.), you should put in an assert that you depend on T being a pointer type, using std::is_pointer and static_assert, and you should use static_cast rather than C-style casts in your interface methods. The C style cast would let someone do Node<SomeTypeBiggerThanVoidPtr>, and it would compile, but explode at runtime.
As the other answers and comments said, use std::forward_list, or another existing library. If you refuse, this is more like I would do:
#include <stdio.h>
struct NodeImpl
{
NodeImpl *next;
void *data;
public:
// we have pointers, so fulfill the rule of three
NodeImpl() : next(NULL), data(NULL) {}
~NodeImpl() {}
NodeImpl& operator=(const NodeImpl& b) {next = b.next; data = b.data; return *this;}
// This function now a member. Also, I defined it.
void* getLastItem()
{
if (next)
return next->getLastItem();
return data;
}
void* getData() {return data;}
void setData(void* d) {data = d;}
};
// the template _inherits_ from the impl
template <typename T>
struct Node : public NodeImpl
{
Node<T> operator=(const Node<T>& b) {NodeImpl::operator=(b);}
// we "redefine" the members, but they're really just wrappers
T* getLastItem()
{ return static_cast<T*>(NodeImpl::getLastItem());}
T* getData() {return static_cast<T*>(NodeImpl::getData());}
void setData(T* d) {NodeImpl::setData(static_cast<void*>(d));}
//or, if you prefer directness...
operator T*() {return static_cast<T*>(NodeImpl::getData());}
Node<T> operator=(T* d) {NodeImpl::setData(static_cast<void*>(d));}
};
struct A { };
struct B { };
int main()
{
Node<A> as; //why were these heap allocated? The root can be on the stack
A *a = as.getLastItem();
Node<B> bs; //also, we want a each node to point to a B, not a B*
B *b = bs.getLastItem();
B* newB = new B;
bs = newB; //set the data member
newB = bs; //read the data member
}
http://ideone.com/xseYk
Keep in mind that this object doesn't encapsulate next or data really, so you have to manage all of that yourself.
I compiled the following cords with g++
#include <iostream>
#include <string>
using namespace std;
template<class T>
class Node<const char*>{
private:
string x_;
Node* next_;
public:
Node (const char* k, Node* next):next_(next),x_(k){}
string data(){return x_;}
Node *get_next(){return next_;}
};
$ g++ -c node01.cc
node01.cc:5: error: ‘Node’ is not a template
What's wrong?
I'm begginer for c++
You're mixing up declarations and instantiations. When you declare a template, you don't specify a type immediately after its name. Instead, declare it like this:
template<class T>
class Node {
private:
const T x_;
Node *next_;
public:
Node (const T& k, Node *next) : x_(k), next_(next) { }
const T& data(){return x_;}
Node *get_next(){return next_;}
};
Your original declaration also confuses string, const char *, and generic types that should be in terms of T. For a template like this, you probably want to let the user define the type of the member (x_). If you explicitly declare it as const char * or string, you're losing genericity by limiting what the user can use for T.
Notice that I changed the types of the instance variables, the parameters of the constructor and the return type of data() to be in terms of T, too.
When you actually instantiate a variable of the template type, you can provide a concrete type parameter, e.g.:
int main(int argc, const char **argv) {
Node<char*> *tail = new Node<char*>("tail", NULL);
Node<char*> *node = new Node<char*>("node", tail);
// do stuff to mynode and mytail
}
Whenever you write the template name Node outside the template declaration, it's not complete until you provide a value for the parameter T. If you just say Node, the compiler won't know what kind of node you wanted.
The above is a little verbose, so you might also simplify it with a typedef when you actually use it:
typedef Node<char*> StringNode;
int main(int argc, const char **argv) {
StringNode *tail = new StringNode("tail", NULL);
StringNode *node = new StringNode("node", tail);
// do stuff to mynode and mytail
}
Now you've built a linked list of two nodes. You can print out all the values in the list with something like this:
for (StringNode *n = node; n; n = n->get_next()) {
cout << n->data() << endl;
}
If all goes well, this will print out:
node
tail
Your class declaration should look like this:
template<class T>
class Node{
private:
T x_;
Node* next_;
public:
Node (const T& k, Node* next):next_(next),x_(k){}
T data(){return x_;}
Node *get_next(){return next_;}
};
Notice how I removed all references to string or const char * and replaced them with the generic type T. Your class, since it is templated, should not refer to any specific type but should do everything in terms of the generic T type.
The const char * is specified later when you declare a Node variable. Or it could be any other type, not just const char *. The point is, when you're declaring the Node class you just use the generic type T in the code without reference to any specific type. You specify a specific type only when you actually use a Node.
Node<const char *> stringNode("foo", NULL);
Node<int> intNode(5, NULL);
This has allowed us to have a single definition of the Node class but be able to use it to create both nodes where the data is a string and nodes where the data is an integer. Hooray templating!