C++ Template Limiting Member Constructor - c++

This is my first foray into C++ templates, and I'm trying to construct a BinaryTree template to help me with a Project Euler problem; however, I seem to be getting an error where BinaryTree class doesn't recognize all the constructors of the BinaryTreeNode! Here's a snippet of the code.
template <class T>
class BinaryTreeNode
{
private:
BinaryTreeNode<T>* _left;
BinaryTreeNode<T>* _right;
T* _value;
public:
BinaryTreeNode();
explicit BinaryTreeNode(const T& value) : _value(&(T(value))) {}
BinaryTreeNode(BinaryTreeNode<T>& left, BinaryTreeNode<T>& right, const T& value) :
_left(&left), _right(&right), _value(&(T(value))){}
};
The BinaryTree class
#include "BinaryTreeNode.h"
template <class T>
class BinaryTree
{
private:
BinaryTreeNode<T>* _root;
BinaryTreeNode<T>* _current;
unsigned int size;
public:
BinaryTree() : size(0), _root(0), _current(0) { }
explicit BinaryTree(BinaryTree<T>& leftTree, BinaryTree<T>& rightTree, const T& value) :
size(leftTree.Size() + rightTree.Size() + 1), _root(leftTree.Root(), rightTree.Root(), value), _current(_root) {}
explicit BinaryTree(const T& value) : size(1), _root(value) {}
const BinaryTreeNode<T>& Root() const { return *_root;}
};
I'm getting these errors.
error C2359: 'BinaryTree<T>::_root' : member of non-class type requires single initializer expression
error C2440: 'initializing' : cannot convert from 'const int' to 'BinaryTreeNode<T> *'
error C2439: 'BinaryTree<T>::_root' : member could not be initialized
The BinaryTreeNode constructor of (BinaryTreeNode<T>&, BinaryTreeNode<T>&, const T& value) works when I include it in my main code, but it doesn't seem to work under my BinaryTree template. Anyone know why?

In your initialization expression _root(leftTree.Root(), rightTree.Root(), value), _root is a pointer. You can only initialize it to another pointer. Perhaps you mean to initialize it to a pointer to a new node constructed on those arguments?
This could be done like this: (updated after your edit)
_root(new BinaryTreeNode<T>(leftTree.Root(), rightTree.Root(), value))
However, this is very dangerous (think about an exception in the allocation), and you should probably avoid using raw pointers in your class design and instead use smart managing pointers.
Similarly, the initializer _root(value) does the wrong thing, you might want:
_root(new BinaryTreeNode<T>(value))
(Also note that you should initialize members in their order of declaration.)
Update: I changed the first constructor call following your edit, but as #Luc says, your constructors take non-const arguments but Root() only provides a const reference, so you still need to fix that.

You have missed ; after both class declarations!
template <class T>
class BinaryTreeNode
{
private:
BinaryTreeNode<T>* _left;
BinaryTreeNode<T>* _right;
T* _value;
public:
BinaryTreeNode();
explicit BinaryTreeNode(const T& value) : _value(&(T(value))) {}
BinaryTreeNode(BinaryTreeNode<T>& left, BinaryTreeNode<T>& right, const T& value) :
_left(&left), _right(&right), _value(&(T(value))){}
};
template <class T>
class BinaryTree
{
private:
BinaryTreeNode<T>* _root;
BinaryTreeNode<T>* _current;
unsigned int size;
public:
BinaryTree() : size(0), _root(0), _current(0) { }
explicit BinaryTree(BinaryTree<T>& leftTree, BinaryTree<T>& rightTree, const T& value) :
size(leftTree.Size() + rightTree.Size() + 1), _root(leftTree.Root(), rightTree.Root(), value), _current(_root) {}
explicit BinaryTree(const T& value) : size(1), _root(value) {}
};

I believe that you need a constructor in the form BinaryTree<T>();

Related

Returning a struct pointer from class method

EDIT: Changed example code to code from my project that doesn't work.
I'm writing code in C++, learning templates and got stuck with some problem.
There's a class:
template<class T, class Cmp>
class AVLtree {
public:
AVLtree(const Cmp& _cmp) : root(nullptr), cmp(_cmp) {}
AVLtree(const AVLtree& ref);
~AVLtree();
AVLtree& operator = (const AVLtree& ref);
void Add(const T& key);
void TraverseDfs(void (*visit)(const T& key));
private:
struct Node {
Node* left;
Node* right;
T key;
int balance;
unsigned int height;
unsigned int inheritence;
Node(const T& _key) : left(nullptr), right(nullptr), key(_key), balance(0), height(1), inheritence(1) {}
};
Node* root;
Cmp cmp;
void deleteTree(Node* root);
void traverse(Node* node, void(*visit) (const T& key));
Node* addNode(Node* node, const T& key);
Node* removeNode(Node* p, T key);
int bfactor(Node* node);
unsigned int height(Node* node);
void fixheight(Node* node);
Node* rotateRight(Node* p);
Node* rotateLeft(Node* q);
Node* balance(Node* p);
Node* findmin(Node* p);
Node* removemin(Node* p);
};
I want to define method addNode(Node* node, const T& key) out of class and here's what I write:
template<class T, class Cmp>
AVLtree<T, Cmp>::Node* AVLtree<T, Cmp>::addNode(Node* node, const T& key) {
return new Node(key);
if (!node) {
return new Node(key);
}
if (cmp(key, node->key)) {
node->left = addNode(node->left, key);
}
else {
node->right = addNode(node->right, key);
}
}
Then I try to run program and get such errors and warnings:
warning C4346: 'Node': dependent name is not a type
message : prefix with 'typename' to indicate a type
error C2061: syntax error: identifier 'Node'
error C2143: syntax error: missing ';' before '{'
error C2447: '{': missing function header (old-style formal list?)
It seems that I'm doing something wrong because, if I define method addNode(Node* node, const T& key) inside class, it works fine:
template<class T, class Cmp>
class AVLtree {
public:
...
private:
...
Node* addNode(Node* node, const T& key) {
return new Node(key);
if (!node) {
return new Node(key);
}
if (cmp(key, node->key)) {
node->left = addNode(node->left, key);
}
else {
node->right = addNode(node->right, key);
}
}
};
Any guesses what might be wrong?
Thanks for answers. Got a solution:
Just added typename before method definition outside of class. It looks like this:
template<class T, class Cmp>
typename AVLtree<T, Cmp>::Node* AVLtree<T, Cmp>::addNode(Node* node, const T& key) {
...
}
It seems that this is some spicialization of Visual Studio because I can see that other compilers work fine with such code without any errors.
It seems that I'm doing something wrong
No. This is a famous "bug/feature" from oldish version of Microsoft's compiler.
Inside the body of C1<T>::Work definition, the name lookup for Node is supposed to find C1<T>::Node. See Name lookup on cppreference.com for more information:
Member function definition
For a name used inside a member function body, a default argument of a member function, exception specification of a member function, or a default member initializer, the scopes searched are the same as in class definition, except that the entire scope of the class is considered, not just the part prior to the declaration that uses the name. For nested classes the entire body of the enclosing class is searched.
Your code is accepted by other compilers, e.g. gcc:
template<class T>
class C1 {
public:
void CallWork() { Work(); }
private:
struct Node {
T x;
};
Node* Work();
};
template<class T>
C1<T>::Node* C1<T>::Work()
{
return new Node{1};
}
live demo

C++ How to initialize a struct through no argument constructor

Node is a struct which defined in a class List_set private.
struct List_set::Node
{
element_t str_l;
link_t next_ptr ;
static link_t* find(link_t* current, element_t string_t);
Node();
};
List_set::List_set():link_(nullptr)
{}
List_set::Node::Node():next_ptr{0}
{}
I want to use a constructor to initialize the Node, however the compiler always report an error:
no matching constructor for initialization of 'list_set::List_set::Node'
Can you please help to figure it out?
The next is the definition of class List_set hope it can provide some reference.
class List_set
{
public:
using element_t = std::string;
List_set();
List_set(std::initializer_list<element_t>);
bool is_empty() const;
size_t size() const;
bool contains(const element_t&) const;
void insert(element_t);
private:
struct Node;
using link_t = std::shared_ptr<Node>;
link_t link_;
};

iterator on map of pointers to objects as a key c++

i'm implementing a backtracking algorithm to solve sudokus, but i have some issues using maps.
could any one tell me why i get these two errors when compiling my code? the first error is about the line declaring the iterator on the map. the second one is when doing Adj[&node] = mList;
the errors:
Error C2664 'std::_Tree_const_iterator>>> std::_Tree>::find(Node *const &) const' : can't convert argument 1 from 'const Node *' to 'Node *const &'
Error C2679 '[' binary : no operator found accepting a right operand of type 'const Node *' (ou there's no acceptable conversion)
(my Visual studio is in french, so i translated the error messages. hope it's fine like this)
my code where i got the error:
template<class T>
void AdjList<T>::addElement(const Node<T>& node, const vector<Node<T>>& vecOfNeighbours) {
typename map< Node<T>*, LinkedList<T>>::iterator mit = Adj.find(&node);
if (mit!=Adj.end()) {
LinkedList<T> mList;
for (typename vector<Node<T>>::const_iterator it = vecOfNeighbours.begin(); it != vecOfNeighbours.end(); it++) {
mList.Add((*it).getValue()[0]);
}
Adj[&node] = mList;
}
}
my classes définitions :
template<class T>
class AdjList
{
private:
map<Node<T>*, LinkedList<T>> Adj;
public:
AdjList();
AdjList(const AdjList<T>& adjlist);
AdjList(const Node<T>& node, const vector<Node<T>>& vecOfNeighbours);
void addElement(const Node<T>& node, const vector<Node<T>>& vecOfNeighbours);
void Print() const;
};
template<class T>
class LinkedList
{
Node<T>* head;
int getEndList();
Node<T>* returnFrontEnd(void) const;
public:
LinkedList();
LinkedList(T data);
LinkedList(const LinkedList<T>& list);
LinkedList<T>& operator=(const LinkedList<T>& list);
void Add(T data);
void AddAt(int index, T data);
void Print();
~LinkedList();
};
template<class T>
class Node
{
protected:
vector<T> _value;
Node<T>* child;
public:
Node(T value);
void addValue(T value);
Node<T>* clone() const;
Node(const Node<T>& node);
vector<T> getValue() const;
Node<T>* returnChild() const;
void AddChild(const Node<T>& node);
Node& operator=(const Node<T>& node);
~Node();
};
You need to cast away const. Why? Take a look:
void AdjList<T>::addElement(const Node<T>& node, const vector<Node<T>>&)
Okay, so node is a const reference,
typename map< Node<T>*, LinkedList<T>>::iterator mit = Adj.find(&node);
But this iterator will have a non-const pointer. So if this were allowed, you'd be able to get a non-const pointer from a const reference. That clearly requires casting away const (which you don't do).

linked list operator overloading issue

i tried to build up my own linked list class and got a problem with the = operator overloading. as far as i know, we should use const parameter when overloading the assignment operator, say using linked_list<T>& operator=( const linked_list<T>& a). however, the complier gave me errors unless i put linked_list<T>& a instead. the complier would stop at
if(this->head==a.front()), giving me Error
11 error C2662: 'linked_list<T>::front' : cannot convert 'this' pointer from 'const linked_list<T>' to 'linked_list<T> &'
below are the details.
#ifndef _LINKED_LIST_H_
#define _LINKED_LIST_H_
template <class T>
struct node
{
T data;
node<T>* next;
};
template <class T>
class linked_list
{
private:
node<T>* head;
public:
linked_list<T>();
linked_list<T>(const linked_list<T>& a);
~linked_list<T>();
linked_list<T>& operator=(const linked_list<T>& a);
bool isEmpty();
int size() const;
void insert_front(T a);
void insert_end(T a);
void erase_end();
void erase_front();
void print() const;
void erase(node<T>* a);
node<T>*& front()
{
node<T>* ptr = new node<T>;
ptr = head;
return ptr;
}
void setFront(node<T>* a);
};
#endif
template <class T>
linked_list<T>& linked_list<T>::operator=(const linked_list<T>& a)
{
if (this->head == a.front()) // the error mentioned happened here. however,
// if no const in the parameter, it would be
// no error
{
return *this;
}
while (head != nullptr) erase_front();
node<T>* copy;
copy = a.front();
while (copy->next != nullptr)
{
insert_end(copy->data);
copy = copy->next;
}
return *this;
}
anybody can help? thanks.
When an accessor returns a reference to an owned structure, it's usually a good idea to implement two versions: One which is non-const and returns a non-const reference, and one which is const and returns a const reference. That way it can be used in both mutating and non-mutating contexts. front() would be a good candidate for this.
Though a side note -- you probably don't want to expose your nodes in the public linked_list interface, particularly non-const references to them. That's the sort of thing to encapsulate entirely in the class.
The problem is that front() is not a const member function, and you're trying to call it on a const instance.

Node implementation Binary Tree

I have the following implementation for the node class:
template<class T> class binTree; // forward declaration
template<class T> class Node {
friend class binTree<T>; // class binTree is friend
public:
//default constructor
Node(const T& d = T(), Node<T> *l = NULL, Node<T> *r = NULL) : data(d),
left(l), right(r) {};
private:
T data;
Node<T> *left, *right;
};
I'm trying to define a new node a the root of my tree, but I keep getting compilation errors...
template<class T>
void binTree<T>::insert(Node<T>*& n, const T& d){
if(n == NULL)
root = Node<T>(d);
}
I'm confused by the const T& d = T() parameter.
I think you just need to declare the binTree class and its members before you try to define the member. The following code compiles for me:
#include <cstdlib>
template<class T> class binTree; // forward declaration
template<class T> class Node {
friend class binTree<T>; // class binTree is friend
public:
//default constructor
Node(const T& d = T(), Node<T> *l = NULL, Node<T> *r = NULL) : data(d),
left(l), right(r) {};
private:
T data;
Node<T> *left, *right;
};
template <class T> class binTree
{
public:
binTree() { }
void insert(Node<T>*& n, const T& d);
private:
Node<T> root;
};
template<class T>
void binTree<T>::insert(Node<T>*& n, const T& d){
if(n == NULL)
root = Node<T>(d);
}
int main(int argc, char **argv)
{
Node<int>* nt;
binTree<int> btree;
btree.insert(nt, 4);
}
Having said this, your concept of the data structure seems messed up. Why does the insert routine in binTree require a node argument?
I'm not quite sure why you have that default override for the d variable in your default constructor. In my implementation of a Node for my Tree class, I had no default assignment. I think the issue is T(). I would recommend not trying to do that default assignment in the params listing, but instead do it in the BMI List. So it would look kind of like "data(new T), left(NULL), right(NULL)"
Additionally I would say I'm not quite certain as to why you are using T(). If that doesn't work, please post the error code so that we can have a better understanding of what is going on.