C++ Generic Tree Comparing by Two Criteria - c++

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.

Related

can c++ store this? template <typename T> (store the typename T so I can reuse it later?)

#include <iostream>
template <typename T>
class Item {
public:
T item;
void* ptr = nullptr;
Item(T var): item(var) {}
unknown next(){
if ((unknown*)ptr != nullptr){
std::cout<<"It is not a null pointer!"<<std::endl;
return (unkown*)ptr
}else{
std::cout<<"It is a null pointer..."<<std::endl;
return NULL
}
}
template <typename temp>
void pass(temp *var){
ptr = var;
}
};
int main() {
Item<int> i(100);
Item<float> n(200.0);
i.pass(&n);
i.next();
}
My problem is to "remember" the type T so I can replace unknown.
I need the void* pointer to point to an unknown type, and I need to type-cast to the right type to retrieve what I stored in it. When the Item was created, nothing was registered (nothing should be registered).
If somehow you guys know how to do that, is it possible to also change the type "remembered" during compile time?
pass as a template could receive an infinite number of types, while the return type of next is fixed to a single type. You are asking for a way to treat all types as a single type, and unfortunately void* is the only way to go; you cannot recover the type used in pass.
I'm not 100% certain of what all your use cases of this class are, so I'll describe a few type-erasure techniques you should look into:
Consider using a std::variant and putting the onus of what to do with the contained type into a visitor defined by the user. e.g., Item<int, double> stores a variant<int, double>
Alternatively, use a std::any and put the onus of recovering type information onto the caller.
Alternatively, enforce type-erasure via polymorphism; instead of void*, own a pointer to a base class.
Another type-erasure approach is Sean Parent's "run time polymorphism" approach, where the user provides an implementation of the required behavior as a function that can be discovered through Argument-Dependent Lookup. Via internal-only polymorphism, you can call the appropriate function for the contained pointer (not too different from how std::function is implemented).

Storing multiple types and returning single type on request

I need to create a class that stores multiple User defined types. It should return one of them, on demand. Is there a way to implement one function to return all the types?
Please note: I cannot use Boost libraries. I need to implement in Visual Studio
class One {};
class Two {};
class Three {};
enum Type
{
OneType,
TwoType,
ThreeType
};
class GenericType
{
template <typename T> // --- How to implement this function
T getValue(Type type)
{
switch(type)
{
case One: return oneType; // Error
case Two: return twoType;
case Three: return threeType;
}
}
shared_ptr<OneType> oneType;
shared_ptr<TwoType> twoType;
shared_ptr<ThreeType> threeType;
Type m_type;
};
In C++11 you have an std::tuple class that does the job. You can retrieve needed element with std::get, like this:
// Create a tuple
std::tuple<std::shared_ptr<OneType>, std::shared_ptr<TwoType>> tuple{null, null};
// Get element
std::get<std::shared_ptr<OneType>>(tuple)
This declaration,
template <typename T> // --- How to implement this function
T getValue(Type type)
… where Type is an enum, makes the run time choice of argument determine the compile time choice of function result type, or alternatively requires the run time selection of argument value to be compatible with the compile time choice of type.
The former is backward in time, so it's not on, and the latter is just silly.
If an ordinary function template is OK for you, then the solution is simple: specialize it for each relevant type.
If you need to have run time selection, then instead use a common result wrapper type. For value semantics it can be a class with union members, i.e. a discriminated union. For reference semantics it can be a pointer to a common base class of the possible result types.

How to create user defined type template class object C++

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.

C++ / Template / Explicit init of template type?

Assume the following dummy template:
template < class DataType > class Dummy
{
public:
void init( )
{
m_data = DataType( 0 );
}
private:
DataType m_data;
};
Calling init will init the internal data. This does work fine when DataType is a standard data type (e.g. int or float). When DataType is a class this class must have a corresponding constructor.
Now assume DataType shall be e.g. a Complex Number represented by a suitable class. In this case it does not make sense to give the Complex number class a constructor with one argument because under normal conditions you want initialize real and imaginary part.
So my question is:
What is the best generic way to initialize a template type under consideration that the template shall be suitable to store any data type.
I think e.g. the STL must implement thinks like this but I am lost within that code.
In your example I guess you meant:
DataType( 0 );
Not:
Data ( 0 );
In any case, try:
m_data = DataType();
That will call the default constructor for a class type, or will zero-init for a built-in type.
You could make use of a default argument as:
template <class T>
class A
{
public:
void init(T c = T()) //default argument
{
m_data = c;
}
private:
T m_data;
};
If template argument type T is a user-defined type, and it does not define a default constructor, then you have to pass one argument to init() function yourself, otherwise you will get compilation error.
This is the approach adopted by Standard Library. For example std::vector::resize() takes an optional argument following the same rationale as mentioned above.
Effectively, you are thinking in terms of "default constructible" classes here, that is, classes that can be initialized with effectively no class-specific input. The STL is written with this term in mind, and as #DanielEarwicker wrote, the default constructor is defined for built-in types as a zero-initialization.
So, to get such a feature, your complex number class must support a default constructor, i.e. a constructor without arguments.

Linked list with different elements , possible?

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
}