Function as argument with default value - c++

I want to create class for binary trees:
struct TreeNode {
explicit TreeNode(int _value) : value(_value) {}
int value = 0;
TreeNode* left = nullptr;
TreeNode* right = nullptr;
};
class BTree {
public:
void Add(int value);
void PrintPostOrder(void (*func)() = print_current);
~BTree();
private:
TreeNode* root = nullptr;
void print_current();
void delete_node();
};
BTree::~BTree() {
PrintPostOrder(delete_node);
}
My idea - for destructor and for Printing I need to do binary tree traversal. So I want to create function Traversal and use function as parameter in it:
if I need to print func = print and for destructor func = delete_node.
Error is here:
void PrintPostOrder(void (*func)() = print_current);
the default argument of type "void (BTree :: ) ()" is incompatible
with the parameter of type "void () ()"
I don't know how to set default value for parameter when parameter is a function.

print_current and delete_node are member functions, so you need a member function pointer:
class BTree {
public:
void PostOrder(void (BTree::*fn)() = &BTree::print_current) {
std::invoke(fn, this);
}
~BTree() {
PostOrder(&BTree::delete_node);
}
private:
void print_current();
void delete_node();
};
For more flexibility you can make PostOrder a template:
struct TreeNode {};
class BTree {
public:
template<class Fn>
void PostOrder(Fn fn) {
std::invoke(fn);
}
void PostOrder() {
PostOrder([this] { print_current(); });
}
~BTree() {
TreeNode* node;
PostOrder([this, node] { delete_node(node); });
}
private:
void print_current();
void delete_node(TreeNode*);
};

In principle you set a default parameter for a function the way you did. The problem is that a member function is of different type than a free function.
This is a free function pointer void (*func)(), while print_current is a member function of type void (BTree :: ) ().
Either fix the parameter type or use a free function as default parameter.
Also do not forget that member functions are fundamentally different from free functions, because you need an instance to call them.

Related

Returning a non-const reference causes a binding reference error

I've implemented a double linked list using weak and smart pointers. The program is working but I have doubts about that const in the getPrev signature method. If I put const a the end of the method signature it will cause a binding reference error
error: binding reference of type 'std::weak_ptr<Node<Integer> >&' to 'const std::weak_ptr<Node<Integer> >' discards qualifiers
return prev;
Wasn't the purpose of that const to mark *this as const ? The return type is non-const for my understanding.
Here is the code, main.cpp:
#include <memory>
#include <iostream>
#include "DoubleLinkedList.h"
class Integer {
private:
int number;
public:
Integer(int number) : number(number) {}
int get() { return number; }
};
int main() {
DoubleLinkedList<Integer> list;
list.insert(Integer(1));
list.insert(Integer(2));
list.insert(Integer(3));
list.insert(Integer(4));
list.insert(Integer(5));
return 0;
}
DoubleLinkedList.h
#include <memory>
#include <vector>
#include <iostream>
template <typename T>
class Node {
private:
T data;
std::weak_ptr<Node> prev;
std::shared_ptr<Node> next;
public:
Node(): data(0) {}
Node(const T &object) : data(object) {};
T getData() const {
return data;
}
void setData(T data) {
Node::data = data;
}
std::weak_ptr<Node> &getPrev() const {
return prev;
}
void setPrev(const std::weak_ptr<Node> &prev) {
Node::prev = prev;
}
std::shared_ptr<Node> &getNext() {
return next;
}
void setNext(const std::shared_ptr<Node> &next) {
Node::next = next;
}
};
template <typename T>
class DoubleLinkedList {
private:
std::shared_ptr<Node<T>> header;
std::weak_ptr<Node<T>> trailer;
int size;
public:
DoubleLinkedList() : size(0) {}
void insert(const T &value) {
auto node = std::make_shared<Node<T>>(value);
if (size++ == 0) {
header = node;
} else {
auto last = trailer.lock();
last->getNext() = node;
node->getPrev() = last;
}
trailer = node;
}
};
If you are inside a const method, all the data members are considered const.
That is, inside this function:
std::weak_ptr<Node> &getPrev() const
you can imagine the member variables like this:
const T data;
const std::weak_ptr<Node> prev;
const std::shared_ptr<Node> next;
It should be clear that you cannot return a non-const reference to a const object:
const int x;
int& getX()
{
return x; // error
}
The reference would allow you to modify x even though it is const, so this is forbidden (formally: a non-const reference cannot bind to a const object).
Inside a const member function of Node, prev is a const std::weak_ptr<Node>, so a std::weak_ptr<Node>& cannot bind to it for the exact same reason.
It appears that within insert you do intend to modify node (by changing its prev value), in which case the getPrev function should not be const (because you intend to modify the object). But this kind of access should probably be reserved for the DoubleLinkedList and not some arbitrary outside user. It then becomes a question of interface design: Which parts of your code are implementation details and how those should be hidden from users? Which parts are the interface that users should interact with (with minimal opportunity for breaking things)?

C++ Is it possible to create a private link between objects?

As far as I can understand, linked list can only implemented with an outsider class. Because a class can't have a member varable of it's own type and a node list need that type. The problem is, if the link is intented to be used by a specific class. If, the link class created outside, it will be available to be created as a standalone object.
It's okay if the link class/struct is a pure link object because it can be used for linking another object type. But, in case I need a link that has a functionallity that only related to a certain object, the public availability of it will be pointless. And I think it's better to be created as a private.
Let's take a look at this declaration:
#include <unordered_map>
using namespace std;
template<class T>
class Node
{
public:
Node();
Node(const T& item, Node<T>* ptrnext = NULL);
T data;
// access to the next node
Node<T>* NextNode();
// list modification methods
void InsertAfter(Node<T>* p);
Node<T>* DeleteAfter();
Node<T> * GetNode(const T& item, Node<T>* nextptr = NULL);
private:
Node<T> * next;
unordered_map<string, T*> nodeList;
};
The unordred_map<string,T*> member can only have meaning with a certain object. So, it will be pointless for Node class to be available outside.
Is it possible? Or maybe is it a bad idea to add a non-generic funtionallity for link class?
class A {
A* m_pnext = nullptr;
public:
inline A* next() { return m_pnext; }
inline void set_next(A*ptr) { m_pnext = ptr; }
}
template <class type>
class LinkedList {
type *m_pfirst = nullptr;
public:
void add(type * ptr) {
if ( nullptr == m_pfirst ) {
m_pfirst = ptr;
} else {
type * n = m_pfirst, p = m_pfirst->next;
while (nullptr != p) {
n = p;
p = n->next();
}
n->set_next(ptr);
}
}
};
Plenty of room for improvement, of course. I'll let you exercise your mind.

C++ reversePrint Linked List Recursively

Here's the reversePrint function:
void SinglyLinkedList::reversePrint(Node* p)
{
if (p == NULL) {
return;
} else {
reversePrint(p->next);
cout << p->data << " ";
}
}
(i.e: list = 1 -> 2 -> 3 -> 4, print out = 4 3 2 1 )
It will only work if *p initially points to what *head points to, namely the first node 1. However, Node* head is a private member of SinglyLinkedList class thus can't be accessed outside the class. How can I pass a pointer that points to head from main ?
Here's what I'm talking about:
int main() {
SinglyLinkedList *list = new SinglyLinkedList();
list->addNode(1);
list->addNode(2);
list->addNode(3);
list->addNode(4);
Node* p = head; // <---- Xcode says: Use of undeclared identifier 'head'
list->reversePrint(p);
return 0;
}
I tried to point *p to what *head points to from inside the reversePrint method. But, it disrupted the recursion
class SinglyLinkedList {
public:
// constructor
SinglyLinkedList();
// destructor
~SinglyLinkedList();
// public APIs
void print();
void addNode(int number);
void reversePrint(Node* p);
private:
Node* head;
};
Move the member function that works with a Node* to the private section.
Create a public member function that does not take any input. Implement it using the private member function.
void SinglyLinkedList::reversePrint()
{
this->reversePrint(this->head);
}
Call the public member function without the Node* in calling function.
list->reversePrint();
You can define one public method without parameters and another private method with a parameter that is called from the public method. For example
public:
void reversePrint() const { reversePrint( head ); }
private:
void reversePrint(Node* p) const { /*...*/ }
Make void SinglyLinkedList::reversePrint(const Node* p) const private,
and add a public overload void SinglyLinkedList::reversePrint() const which calls reversePrint(head).
Alternatively, you may add getter to head.

how to preserve const correctness across pointers?

I am trying to have a const operation on a class that is truly const - it does not change data that the class points to.
For example:
class Node{
public:
int val;
};
class V{
public:
Node * node; //what is the change that is needed here?
void const_action()const{
node->val=5; //error wanted here
}
void action(){
node->val=5; //error is not wanted here
}
};
You can use a template to enforce the const correctness on a pointer without changing the meaning or the implementation of your class:
template <typename T>
class PreseveConstPointer
{
T *t_;
public:
PreseveConstPointer(T *t = nullptr)
: t_(t)
{
}
PreseveConstPointer<T> * operator=(T *t)
{
t_ = t;
return this;
}
T* operator->()
{
return t_;
}
T const * operator->() const
{
return t_;
}
T * data()
{
return t_;
}
};
class Node{
public:
int val;
};
class V{
public:
PreseveConstPointer<Node> node;
V()
{
node = new Node;
}
~V()
{
if(node.data())
delete node.data();
}
void const_action()const{
node->val=5; // You will get an error here
}
void action(){
node->val=5; // No error here
}
};
const after a function declaration says that the function is not allowed to change any class members (except ones that are marked mutable).
Since your code doesn't change any class member, and only changes the object node points to, both function will compile.
AFAIK there's no way to prevent this. If you mark the node const, neither will compile.
You're confusing Node* const for Node const*.
An [unfortunate?] side effect of using indirection here is that constness of the pointer member has nothing to do with the actual Node on which you're operating.
If you don't need that member to be a pointer, then this is pleasingly easy:
class V
{
public:
Node node;
void const_action() const
{
node.val = 5; // error here
}
void action()
{
node.val = 5; // no error here
}
};
However, given its name, I suspect life is not that simple and you are basically out of luck.

Just a few simple errors

I am getting a few errors that I don't know about and have spent entirely to much time pulling my hair out. Here is my Header:
#ifndef MYBSTREE_H
#define MYBSTREE_H
#include "abstractbstree.h"
#include "MyBSTreeFunc.h"
using namespace std;
template<typename T>
class TreeNode
{
public:
T m_data;
TreeNode* m_right;
TreeNode* m_left;
};
template<typename T>
class MyBSTree:public AbstractBSTree<T> //LINE 18
{
private:
TreeNode<T>* m_root;
public:
void MyBSTree();
int size() const;
bool isEmpty() const;
int height() const;
const T& findMax() const;
const T& findMin() const;
int contains(const T& x) const;
void clear();
void insert(const T& x);
void remove(const T& x);
void printPreOrder() const;
void printPostOrder() const;
void print() const;
};
#endif
And my implementation file:
Line 1-6
void MyBSTree()
{
m_root -> m_data = NULL;
m_root -> m_right = NULL;
m_root -> m_left = NULL;
}
Line 13-21
template<typename T>
bool MyBSTree<T>::isEmpty() const
{
if (m_root== NULL)
return true;
else
return false;
}
Line 28-35
template < typename T >
const T& MyBSTree<T>::findMax() const
{
TreeNode* p = m_root;
while(p -> m_right != NULL)
p = p -> m_right;
return p;
}
The error for line 3 in the implementation says 'm_root' was not declared in this scope. But it's cool with lines 4 and 5. I'm guessing because m_data isn't a pointer? I don't know.
Next, Line 14, and 21, and quite a few others say that it expected an initializer before the '<' token. I assume they are all the same issue so I only put a few here.
Finally, it says for line 18 in the header: "template struct MyBSTree redeclared as a different kind of symbol." It then says Line 1 of my implementation is a previous declaration of 'void MyBSTree". I am assuming those go together.
Thanks for all the help.
You need to fix your constructor declaration:
template < typename T >
classMyBSTree
{
... // some stuff
public:
MyBSTree(); // no return type
... // some stuff
};
You alse need to fix your constructor:
template < typename T >
MyBSTree::MyBSTree() // proper ctor definition
{
m_root -> m_data = T(); // use the initializer for that data type
m_root -> m_right = NULL;
m_root -> m_left = NULL;
}
Lines 1-6: You've define a standalone function in the .cpp named void MyBSTree(). This is not part of the class. It's also bad that you named the function the same as your class. It looks like you want this to be your constructor, in which case you need this (I won't include the template stuff, as it's not the issue):
// in .h
class MyBSTree {
public:
MyBSTree(); // No void
}
// in .cpp
// Uses MyBSTree namespace.
MyBSTree::MyBSTree() { /* initialize your pointers etc */ }
This seems to be your main issue, and may fix the other problems too.
The reason the compiler cannot find m_roots is because your function is not part of the class. You would fix this by putting your function into the class scope with operator :: (e.g. myBSTree::myBSTree(){};)
Template functions cannot be placed in separate files from their class, you need to define all of your template class and function in the same file. Move the implementation of your functions into your header file.