Hya,
Lemme explain my point.
template<typename T>
class node{
T data;
template<typename X>
node<X>* right; // can point to any node<typename> i know its wrong
}
so that i can do something like:
node<int> a;
a.data = 23;
node<float> b;
b.data =43.6;
a.right= b;
std::cout<< a.data <<a.right->data;
Another example:
template <class Type>
struct vnode {
Type data;
vnode<Type> * vnodenext;
// vrow what_to_put_here // **i don't want to use void ptrs neither want to cast back manually**
}
And in main function if I define vnode struct of type string and another vnode of type int, then what pointer def should I replace with vrow in vnode struct definition so that it can point to vnode of type int or other type of vnode? e.g.
vnode<string> mystring;
vnode<int> myint;
myint.vrow = &mystring
It isn't really possible to do what you want because when using templates you have to know the types involved at compile time. In contrast, walking a previously constructed linked list requires you to discover the types in the list at runtime.
To illustrate, consider this:
struct node_base {
virtual ~node_base() {}
}
template<typename T>
struct node : public node_base {
T data;
node_base* right;
}
Now you can certainly have a list of node_base*, and those nodes can contain any type of data that you want. Constructing the list is not a problem, since at the point you add nodes the static type of data is known and you can create a node<TData>.
Now the problem is how to get the data back. Assume that there's a function that returns the data inside a node, given a pointer to that node. What should be the functions return type? Clearly (unless you know from beforehand that all data types share a common base) there is no single type that can be returned. That leaves you with:
Returning a void*
Writing a templated function that receives the data type as an argument
However, #2 is not feasible in practice (although it works in theory). You cannot write the data type as a template argument because that would require you to know it at compile time, which defeats the purpose of a multi-data-type list.
Therefore, the only solution left is returning a pointer type (either a node_base* or a void* to the data itself) and then casting that pointer to a useful type using some mechanism.
In general, it's not possible in C++ without some kind of run-time support. But you can use variant type for the values of nodes, see http://www.boost.org/doc/libs/1_46_1/doc/html/variant.html for example.
You should derive your vnode template from a common ancestor, i.e.
struct vnode_base {
virtual ~vnode_base() {}
};
template <class Type>
struct vnode : vnode_base {
// ...
};
and use the vnode_base* type for the next-element pointers in your nodes. Since conversion rom base class to ancestors is implicit, the following assignment would be fine: a.right= &b;.
To check if a node has a particular type, use C++'s RTTI. There's not really a way to avoid this - you need some kind of runtime type checking.
vnode<float>* pf = dynamic_cast<vnode<float>* >(a.right);
if (pf) {
// here we go
}
Related
I’m trying to make generic binary tree in c++ using templates.
So for example the type of value in Node class could be string, int or double.
I create my tree from the string and in in method I extract e.g single number from string and call constructor for Node.
Node class in header file without rest of the methods:
template <class T>
class Node {
public:
Node(const string value){
this->value = value;
this->leftChild = nullptr;
this->rightChild = nullptr;
};
private:
T value;
Node *parent;
Node *rightChild;
Node *leftChild;
};
So what I’m asking is how to define different constructor for specific type of Node class so e.g it would be possible to do:
Node<int> node(„2”);
and define and call constructor like:
Node(const string value){
this->value = stoi(value);
this->leftChild = nullptr;
this->rightChild = nullptr;
};
Before I was trying to has just one constructor but overload = operator:
void operator=(int &n,string &s){
n = stoi(s);
};
But when it’s defined outside of class, compiler say "overloaded 'operator=' must be a non-static member function"
First off you need to learn about member initializer lists: C++ initializes object directly. So you’d have a ctor like this:
Node::Node(std::string const& value)
: value(value) // this line will need adjustment; see below
, leftChild(nullptr)
, rightChild(nullptr) {
}
For a generic data structure you’d most likely actually adjust the ctor argument type to match the value type. It is unusual that a generic data structure deals with type conversions. However, for the discussion below I’ll assume you want to stick to std::string, e.g., because the values are read from a text file.
If you need to convert between types you’ll want to use a generic type converter. These come in two flavors:
an existing function template like boost::lexical_cast
use a specific customization point
Both approaches have their place and it may be reasonable to even combine them. What they have in common is that the generic code uses identical syntax and the type-specific handling is done elsewhere.
Using boost::lexical_cast
The idea of boost::lexical_cast is to convert the argument to a character sequence, parse the result using a stream to produce the destination type, and yield the result. The actual implementation is heavily optimised to avoid costly operations for common conversions, e.g., the conversiin from std::string to int iis effectively doing the same as stoi().
It would be used like
Node::Node(std::string const& value)
: value(boost::lexical_cast<T>(value))
, leftChild(nullptr)
, rightChild(nullptr) {
}
Using a Customization Point
Another approach is to define a specific customization point, i.e., a generic interface which can be customized by users of the data structure. The advantage of this approach is that there is a bit more flexibility, e.g., to do suitable conversions based on how the data structure is used. Using a suitable default could avoid the drawback that the customization point has to be defined by every user.
Assuming the function used for the conversion is called my_convert it could be used like that (there are other approaches to define customization points, too):
Node::Node(std::string const& value)
: value(my_convert<T>(value))
, leftChild(nullptr)
, rightChild(nullptr) {
}
This approach assumes that there is a primary template defined which probably defines a suitable default, e.g.:
template <typename T>
T my_convert(std::string const& value) {
return boost::lexical_cast<T>(value);
}
It could be customized for a specific target type using template specialization:
template <>
int my_convert<int>(std::string const& value) {
return std::stoi(value);
}
Usually you would make your constructor and other members take T, do you have a reason not to?
template<typename T>
struct Node
{
T value;
Node * left, * right;
Node(T const & value)
: value(value), left(), right()
{ }
...
};
I am starting to work on a generic tree and I am new to C++. I want to be able to form two trees of the same elements, but in each tree to compare in a different manner. From what I could tell if I overload < then I can only define one function. I thought I could perhaps pass a pointer to a function, but I feel like this is the wrong way to go about this.
template<class T, int (*Comp)(T*, T*)> class Tree
What would be an advisable way to try and do that?
Thanks
No, you do not want to specify a pointer to a function (doing so would prohibit using a function object, which is usually preferable).
The template parameter should normally be a type parameter--and in this case you almost certainly want to provide a default of std::less<T>, so it would look something like this:
template <class T, class Comp = std::less<T>>
class Tree {
// Implementation here.
};
This will allow instantiation over a pointer to a function, but (as noted above) will also support a function object.
Note, however, that the template parameter only specifies the type of thing you use to do comparisons. In a typical case, you'll need an instance of that type to do something. You'll typically specify this when you construct your object, so you'll have something like this:
template <class T, class Comp = std::less<T>>
class Tree {
public:
Tree(Comp c = Comp()) : c(c) {}
bool insert(T value) {
if (c(value, root->value)) // if value < root->value
// ...
else if (c(root->value, value)) // if root->value < value
}
private:
struct Node {
T key;
Node *left , *right;
} *root;
Comp c;
};
So, the template parameter specifies the type for the thing that does a comparison. We give it a default of std::less<T>; that'll work nicely for built-in types, and anything else that makes a<b a legitimate expression (assuming we want the comparison that does, of course). If we supply a different type, it's up to use to ensure that it defines a strict weak ordering.
We then pass an instance of the comparison type to the constructor. Again, we specify a default value of a default-constructed instance of that type. For the common case of a function object type like std::less<T> or std::greater<T>, a default constructed object will do the right thing, so that's all we need.
For the less common case of wanting to use a pointer to a function, we have to specify the correct type as the template parameter, and we have to pass a pointer to the correct function to the constructor.
I am struggling with allowing user to select data type template will be created as.
Since template type must be defined on compile, I must specify data type template will use eg(string,int, so on), but that means I cannot change it latter on, from lets say string to int even if my template supports it, because template class object was declared as string.
My class declaration below:
template <class T>
class MyHashTable
{
public:
string deleted="deleted";
unsigned short tableSize;
// array of vectors, hash table container
vector<T>* myTable;
vector<T>* deletionTable;
MyHashTable(unsigned short tableSize) : myTable(new vector<T>[tableSize]), deletionTable(new vector<T>[tableSize])
{
this->tableSize=tableSize;
}
object declaration outside class
MyHashTable <string>* myChainedTable=NULL ;
string tableType;
object initialization
if (myChainedTable)
{
delete myChainedTable;
myChainedTable=NULL;
}
getType();
if (!myChainedTable)
{
if (tableType=="string")
myChainedTable= new MyHashTable<string>(length);
if (tableType=="char")
MyHashTable<char> myChainedTable(length); // no difference with or without using new keyword
if (tableType=="double")
MyHashTable<double> myChainedTable(length);
if (tableType=="float")
MyHashTable<float> myChainedTable(length);
if (tableType=="int")
MyHashTable<int> myChainedTable(length);
cout<<tableType<<" table of size "<< length<<" created"<<endl;
I attempted passing class object to functions instead of having it as global variable, but couldnt get it work either.
What I really need is single template object that can have: int,string,char,double,float types, I have 3 functions that need to have access to template class object, and having 5 different objects and 200 lines of if statements for each situation sounds like worst possible solution.
I been stuck on this for a while and just cant figure out how to do it and any help will be appreciated.
void getType()
{
cout<<"Enter table type, types available: int, char, float, double, string.\n";
tableType=getInput();
while((tableType != "int")&&(tableType !="float")&&(tableType !="double")&&(tableType!="char")&&(tableType !="string"))
{
cout<<"Invalid type, please try again "<<endl;;
tableType=getInput();
}
}
Your question is at the boarder between templates and variants.
The template is compile time. So you have to choose at compile time the type you want for your object. Your conditional approach can't work (see comments to question).
On the other side, you seem to need a dynamic choice of type at runtime.
If you want to go on on template way: (edit based on comments)
You'd need to have all the templates inherit from a single polymorphic base class (one common interface with virtual functions). Example:
class MyHashBase // common base class for all templates
{
public:
virtual void addElement(void *ptrelem) = 0; // adding an element must be implemented by template. With void* since future template type unknown from base class
virtual void displayAll() = 0;
};
The templates would need then implement the virtual functions:
template <class T>
class MyHashTable : public MyHashBase
{
public:
unsigned short tableSize;
vector<T>* myTable; // I leave it as it is, but you could implement these as vector<T> instead of vector<T>*
vector<T>* deletionTable;
MyHashTable(unsigned short tableSize) : myTable(new vector<T>[tableSize]), deletionTable(new vector<T>[tableSize]), tableSize(tableSize)
{ }
void addElement(void* ptrelem)
{ myTable->push_back(*reinterpret_cast<T*>(ptrelem)); } // reinterpret the void* of the common interface as a T*
void displayAll()
{ copy(myTable->begin(), myTable->end(), ostream_iterator<T>(cout, "\n")); }
};
You could then have your myChainedTable be a pointer to the common base type, and intialise this pointer in the way you did with the string case (i.e. using new).
MyHashBase *myChainedTable = nullptr;
//...
if (tableType == "string")
myChainedTable = new MyHashTable<string>(length);
else if (tableType == "double")
myChainedTable = new MyHashTable<double>(length);
//...
You could then use the common API, for example if tableType is "double":
double d1 = 3.1415, d2 = 1.4142;
myChainedTable->addElement(&d1); // ATTENTION: you must ensure to provide pointer to the correct data type
myChainedTable->addElement(&d2);
myChainedTable->displayAll();
You'll certainly have a coupe of if required in the calling code, but you could reduce them to minimum by carefully designing the base class (for example, you could add a virtual clone function, to duplicate the data without need to know the type by the caller).
However, using a single signature for the common functions of the base class is cumbersome. To make the virtualisation possible you need to pass parameters through void* pointer which is not so nice and rather error prone.
Alternate way with variants
You could also use boost variants which are meant for managing objects with dynamic definition of types.
In this case you would not need template for your own data structure. You would create a MyHashTable with elements of type boost::variant< int, std::string, ... >.
You could then access to the right value of the object if you know its type (as in your myChainedTable) by using: boost::get<int> (element) (or boost::get<string>(), ...).
If you don't know the type on an element you could use the concept of "visitor" to chose automatically the appropriate function to exectue depending on the type.
Edit: alternate way with unions:
If you're not allowed to use variants another alternative could be use a union. I don't know the topic of you rassignment, but you have the choice whether you use a union to define the elements (like the variants, without templates) or to use a template type as you did, but define myChainedTable to be a union of pointers to the different template instantiations. But yes, it requires a lot of ifs...
Templates are resolved at compile time. Your container type is resolved at runtime. Templates are clearly not the solution here. The first thing that comes to my mind is a combination of boost::any and std::vector instead.
I hope the headline isn't too confusing. What I have is a class StorageManager containing a list of objects of classes derived from Storage. Here is an example.
struct Storage {}; // abstract
class StorageManager
{
private:
map<string, unique_ptr<Storage>> List; // store all types of storage
public:
template <typename T>
void Add(string Name) // add new storage with name
{
List.insert(make_pair(Name, unique_ptr<Storage>(new T())));
}
Storage* Get(string Name) // get storage by name
{
return List[Name].get();
}
};
Say Position is a special storage type.
struct Position : public Storage
{
int X;
int Y;
};
Thanks to the great answers on my last question the Add function already works. What I want to improve is the Get function. It reasonable returns a pointer Storage* what I can use like the following.
int main()
{
StorageManager Manager;
Manager.Add<Position>("pos"); // add a new storage of type position
auto Strge = Manager.Get("pos"); // get pointer to base class storage
auto Pstn = (Position*)Strge; // convert pointer to derived class position
Pstn->X = 5;
Pstn->Y = 42;
}
It there a way to get rid of this pointer casting by automatically returning a pointer to the derived class? Maybe using templates?
use:
template< class T >
T* Get(std::string const& name)
{
auto i = List.find(name);
return i == List.end() ? nullptr : static_cast<T*>(i->second.get());
}
And then in your code:
Position* p = Manager.Get<Position>("pos");
I don't see what you can do for your Get member function besides what #BigBoss already pointed out, but you can improve your Add member to return the used storage.
template <typename T>
T* Add(string Name) // add new storage with name
{
T* t = new T();
List.insert(make_pair(Name, unique_ptr<Storage>(t)));
return t;
}
// create the pointer directly in a unique_ptr
template <typename T>
T* Add(string Name) // add new storage with name
{
std::unique_ptr<T> x{new T{}};
T* t = x.get();
List.insert(make_pair(Name, std::move(x)));
return t;
}
EDIT The temporary prevents us from having to dynamic_cast.
EDIT2 Implement MatthieuM's suggestion.
You can also further improve the function by accepting a value of the
type to be inserted, with a default argument, but that might incur an
additional copy.
When you have a pointer or reference to an object of some class, all you know is that the actual runtime object it references is either of that class or of some derived class. auto cannot know the runtime type of an object at compile time, because the piece of code containing the auto variable could be in a function that is run twice -- once handling an object of one runtime type, another handling an object with a different runtime type! The type system can't tell you what exact types are in play in a language with polymorphism -- it can only provide some constraints.
If you know that the runtime type of an object is some particular derived class (as in your example), you can (and must) use a cast. (It's considered preferable to use a cast of the form static_cast<Position*>, since casts are dangerous, and this makes it easier to search for casts in your code.)
But generally speaking, doing this a lot is a sign of poor design. The purpose of declaring a base class and deriving other class types from it is to enable objects of all of these those types to be treated the same way, without casting to a particular type.
If you want to always have the correct derived type at compile time without ever using casts, you have no choice but to use a separate collection of that type. In this case, there is probably no point deriving Position from Storage.
If you can rearrange things so that everything that a caller of StorageManager::Get() needs to do with a Position can be done by calling functions that don't specify Position-specific information (such as co-ordinates), you can make these functions into virtual functions in Storage, and implement Position-specific versions of them in Position. For example, you could make a function Storage::Dump() which writes its object to stdout. Position::Dump() would output X and Y, while the implementations of Dump() for other conceivable derived classes would output different information.
Sometimes you need to be able to work with an object that could be one of several essentially unrelated types. I suspect that may be the case here. In that case, boost::variant<> is a good way to go. This library provides a powerful mechanism called the Visitor pattern, which allows you to specify what action should be taken for each of the types that a variant object could possibly be.
Apart from the fact that this looks like a terrible idea... let's see what we can do to improve the situation.
=> It's a bad idea to require default construction
template <typename T>
T& add(std::string const& name, std::unique_ptr<T> element) {
T& t = *element;
auto result = map.insert(std::make_pair(name, std::move(element)));
if (result.second == false) {
// FIXME: somehow add the name here, for easier diagnosis
throw std::runtime_error("Duplicate element");
}
return t;
}
=> It's a bad idea to downcast blindly
template <typename T>
T* get(std::string const& name) const {
auto it = map.find(name);
return it != map.end() ? dynamic_cast<T*>(it->second.get()) : nullptr;
}
But frankly, this system is quite full of holes. And probably unnecessary in the first place. I encourage you to review the general problem an come up with a much better design.
I am implementing something similar to a typed genetic programming and have become a little stuck with regards to C++ types.
I have a network of nodes, nodes have different types, for example some are functional nodes whereas others are just data. In order to deal with collections of such nodes, I saw no option other than to use polymoprphism to store colection of base class pointers.
class Node {
private:
std::string label;
std::string node_type;
};
template
<typename FNC>
class FunctionalNode : public Node {
std::function<FNC> function;
};
class Network {
std::vector<Node*> nodes;
...
}
Note I have a templated FunctionalNode, which stores a std::function, I think (but am not certain) that my problem applies equally if I were to store a plain function pointer instead.
So the problem is, at some point given a Node pointer to a dervied FunctionalNode, I need to apply the stored function to some values. This means I need to cast the base pointer onto the derived class, but since it is templated I am not sure how to do this.
I would like to do something like the following fake C++ code, which would need something like type variables:
Node * applyfunction(Node * functional_node, std::vector<Node*> arguments) {
typevariable function_type = convert_node_type_to_typevariable(functional_node.node_type)
functional_node_derived * = static_cast<function_type>(functional_node);
....
}
Where a node's node_type is some structure I use to contain the type information of the node, e.g. the type of its functional form, and convert_node_type_to_typevariable would convert this to a typevariable I can use in this hypothetical C++ language.
Any ideas how I could implementing this seing as C++ lacks support for type variables, or a completely different approach to the problem?
You should exploit your polymorphic structure. You can define Node with a pure virtual method instead of making applyfunction a free function.
class Node {
protected:
std::string label;
std::string node_type;
public:
virtual ~Node () {}
virtual Node * applyfunction (std::vector<Node *> args) = 0;
};
Then your derivations would perform the work.
template
<typename FNC>
class FunctionalNode : public Node {
std::function<FNC> function;
public:
Node * applyfunction (std::vector<Node *> args) {
//...
}
};