Search code examples
c++templatesmethodssortedlist

How to take care of this error: invalid conversion from 'bool (*)(int)' to 'int'?


I'm writing this code for generic sorted list, and I have to write a filter method, without knowing what type of argument I will get. So I wrote it like that :

#include <iostream>
#include <cstring>
#include <string>
#include <functional>

#include "dummy.h"
using namespace std;

#ifndef SORT_H
#define SORT_H

template <class T>
class LinkedList {
    struct Node {
        Node(const T &in) : data(in) {}
        T data;
        Node * next;
    };

    class Iterator
    {
        Node *m_ptr;              // pointer to current node in the list
    public:
        Iterator(Node * node) {
            m_ptr = node;
        }
        Iterator& operator++() {
            m_ptr = m_ptr -> next();
            return *this;
        }
        Iterator operator++(int) {
            Iterator temp(*this);
            m_ptr = m_ptr -> next();
            return temp;
        }
        bool operator==(const Iterator other) const {
            return m_ptr==other.m_ptr; }
        bool operator!=(const Iterator other) const
        { return m_ptr!=other.m_ptr; }
        string& operator*()
        { return m_ptr->data(); }
        operator bool()
        { return m_ptr!=0; }
    };

    Node * head;

public:
    LinkedList() {
        head = nullptr;
    }
    LinkedList(T value) {
        head -> data = value;
        head -> next = nullptr;
    }

    ~LinkedList() {
        while(head != nullptr) {
            Node * n = head->next;
            delete head;
            head = n;
        }
    }
    void operator = (T &t) {
        head = t.head;
    }

//    LinkedList(LinkedList &list){
//        Node * tmp = list.head;
//        Node * curr = list.head -> next;
//        while (curr) {
//            tmp -> next = (Node*)malloc(sizeof(tmp-> next));
//            tmp -> next = curr;
//            tmp = tmp -> next;
//            curr = curr -> next;
//        }
//    }

    int length() {
        int counter = 0;
        Node * tmp = head;
        while( tmp ) {
            counter++;
            tmp = tmp -> next;
        }
        return counter;
    }

    void insert(T value) {
        if (head == nullptr) {
            head = (Node*)malloc(sizeof(head));
            head -> data = value;
            head -> next = nullptr;
            return;
        }
        Node* n = (Node*)malloc(sizeof(n));
        n -> data = value;

        Node* tmp = head;
        while (tmp != nullptr) {
           if (value > tmp -> data && tmp -> next != nullptr) {
               if (tmp -> next -> data > value) {
                   Node * curr = tmp -> next;
                   tmp -> next = n;
                   n -> next = curr;
                   return;
               } else {
                   tmp = tmp -> next;
               }
           } else if (value > tmp -> data && tmp -> next == nullptr) {
               tmp -> next = (Node*)malloc(sizeof(tmp -> next));
               n -> next = nullptr;
               tmp -> next = n;
               return;
           } else if (value == tmp -> data && tmp -> next == NULL) {
               tmp -> next = (Node*)malloc(sizeof(tmp -> next));
               n -> next = nullptr;
               tmp -> next = n;
               return;
           } else if (value == tmp -> data && tmp -> next != NULL) {
               n -> next = tmp -> next;
               tmp -> next = n;
               return;
           } else {
               n -> next = tmp;
               head = n;
               return;
           }
        }
    }

    void remove(T value) {
        Node* old = head -> next;
        free(head);
        head = old;
    }

    void print() {
        Node *curr = head;
        while (curr) {
            cout << curr->data << endl;
            curr = curr->next;
        }
    }

    Iterator begin() {
        return head->next();
    }
    Iterator end() {
        return 0;
    }
};


#endif

And my main looks like that :

#include <iostream>
#include "sortedList.h"
#include "dummy.h"

bool func(int num) {
    if (num % 2 != 0) {
        return false;
    }
    return true;
}

int main() {
    std::cout << "Hello, World!" << std::endl;

    Dummy teeth(24);
    teeth.add(7);
    Dummy slime(11);
    slime.add(1);
    Dummy josh(32);
    LinkedList<Dummy> teeth_list;
    teeth_list.insert(teeth);
    teeth_list.insert(slime);
    teeth_list.insert(josh);
    int num = teeth_list.length();
    cout << "The length is: " << num << endl;
    teeth_list.remove(slime);
    cout << "Now printing Dummy list" << endl;
    teeth_list.insert(slime);
    LinkedList<Dummy> new_int_list;
    new_int_list = teeth_list;
    teeth_list.print();
    cout << "Now printing new_int_list" << endl;
    new_int_list.print();

    LinkedList <Dummy> dummy1;
    dummy1 = dummy1.filter(teeth_list, &func);

//    LinkedList <Dummy> dummy(teeth_list);
//    cout << "Now printing new_dummy_list" << endl;
//    new_int_list.print();


    return 0;
}

The Dummy class looks like that:

#include <iostream>
#include <cstring>
#include <string>
#include <cmath>

using namespace std;

#ifndef DUMB_H
#define DUMB_H

class Dummy {
    int num_of_teeth;
public:
    Dummy(int num) {
        num_of_teeth = num;
    }
    ~Dummy() {};
    void add(int num) {
        num_of_teeth += num;
    }
    void remove() {
        num_of_teeth --;
    }
    void operator = (Dummy &dumb) {
        num_of_teeth = dumb.num_of_teeth;
    }
    bool operator < ( Dummy &dumb ) {
        return num_of_teeth < dumb.num_of_teeth ? true : false;
    }

    bool operator > ( Dummy &dumb ) {
        return num_of_teeth > dumb.num_of_teeth ? true : false;
    }

    bool operator == ( Dummy &dumb ) {
        if ( dumb.num_of_teeth == num_of_teeth ) {
            return true;
        } else {
            return false;
        }
    }
    void print() {
        int num = num_of_teeth;
        while (num > 0) {
            cout << "D";
            if ((num-1) == (num_of_teeth/2)) {
                cout << "\n";
            }
            num --;
            if (num == 0) {
                cout << "\n";
            }
        }
    }
    friend ostream& operator << (ostream& output, Dummy& dumb)
    {
        output << dumb.num_of_teeth;
        return output;
    }
};

#endif

And when I try to compile it I get the Error:

   ====================[ Build | exe_name | Debug ]================================
"C:\Program Files\JetBrains\CLion 2021.1.1\bin\cmake\win\bin\cmake.exe" --build C:\Users\User\CLionProjects\ex2.2\cmake-build-debug --target exe_name -- -j 3
Scanning dependencies of target exe_name
[ 33%] Building CXX object CMakeFiles/exe_name.dir/main.cpp.obj
In file included from C:\Users\User\CLionProjects\ex2.2\main.cpp:2:
C:\Users\User\CLionProjects\ex2.2\sortedList.h: In instantiation of 'LinkedList<T> LinkedList<T>::filter(LinkedList<T>&, B) [with B = bool (*)(int); T = Dummy]':
C:\Users\User\CLionProjects\ex2.2\main.cpp:36:45:   required from here
C:\Users\User\CLionProjects\ex2.2\sortedList.h:112:21: error: cannot convert 'Dummy' to 'int' in argument passing
             if (pred((curr -> data))) {
                 ~~~~^~~~~~~~~~~~~~~~
mingw32-make.exe[3]: *** [CMakeFiles\exe_name.dir\build.make:81: CMakeFiles/exe_name.dir/main.cpp.obj] Error 1
mingw32-make.exe[2]: *** [CMakeFiles\Makefile2:94: CMakeFiles/exe_name.dir/all] Error 2
mingw32-make.exe[1]: *** [CMakeFiles\Makefile2:101: CMakeFiles/exe_name.dir/rule] Error 2
mingw32-make.exe: *** [Makefile:136: exe_name] Error 2

Where should I change the code to make it work? And how?

**edit: After I changed the function in main to:

bool func(Dummy num) {
    int number = num.get();
    if (number % 2 != 0) {
        return false;
    }
    return true;
}

It compiles but returns an unending list of unknown numbers.. like-

16740248
16711872
16740296
16740248
16711872
16740296
16740248
16711872
16740296
16740248
16711872
16740296
16740248
16711872

Process finished with exit code -1073741510 (0xC000013A: interrupted by Ctrl+C)

Where in the code do I try to reach a forbidden memory? or a corrupted one?


Solution

  • You pass an entire Dummy to the predicate function when you call pred((curr -> data). pred, coming from the line dummy1 = dummy1.filter(teeth_list, &func);, is a function expecting an int, which it doesn't get.

    There are a couple of potential fixes.

    1. Use a function that expects a Dummy (and extracts the teeth itself ;-) ).
    2. Pass the number of teeth (which are currently inaccessible), not the entire Dummy.
    3. Providing a conversion operator to int in Dummy (presumably returning the number of teeth) should work as well.

    The conversion operator approach seemed to work for me. I inserted

        operator int() { return num_of_teeth; }
    

    into the Dummy class in the public section.

    Whether that is good style is debatable. It may be unexpected that a Dummy is also an int. There is perhaps also an argument that the predicate function should work on the entire node data, but that is debatable: A general, reusable function that can handle everything int-oid has its merits as well. Since C++11 you can mitigate the unexpectedness of a conversion to int by making it explicit: It is still possible but requires a static cast.

    As for the rest of the code:

    • Define a proper assignment for the list: head = t.head;— a shallow copy, sharing all nodes — leads to double deletes on each node when the lists go out of scope
    • Do not mix malloc and delete
    • Do not use naked pointers in the first place, use smart pointers
    • Check your insert function, the logic seems overly complicated and may be buggy
    • The Node constructor should also null next
    • You'll likely need const iterators.

    Make sure to write extensive tests for such a container class with wild inserts and deletes, at the beginning, the end etc. Make sure to cover all edge cases with empty lists. Containers are hard to get perfectly correct without rigorous tests.