1

I'm doing some C++ drills to learn the language.

Currently, I'm working on linear data structures, and I'm asked to implement sorting in a linked list without an extra array or structure.

Right now, I'd like to use callbacks in the iterate() function, to be flexible to call a print() function to check the values of a findMin to find the minimum value that will determine the base number for sorting.

I read this pretty useful guide about callbacks: Callback functions in C++, but I can't reference the callback inside of my recursion call inside the iterate() function.

It would be nice to get some help to solve the issue that the comment in the code shows, but if you can let me know which concept I need to review/study, that would be even more helpful for building callback knowledge foundations.

/* Implement sorting in a dynamic linked list without using an additional array or data structure.*/

#include <iostream>

class List{
  typedef struct Node{
    int data;
    Node* next = nullptr;
  }node;
  public:
    List(int data);
    ~List();
    void add(int data);
    void iterate(Node * node, void(*func)());
  private:
    int min = 0;
    Node* root;
    Node* it;
};

List::List(int data){
  root->data = data;
  it = root;
}

List::~List(){}


void List::iterate(Node * node, void(*func)()){
  func();//prints or finds min 
  if(node->next == nullptr)
    return;
  iterate(node->next,&func()); //--compiler says it can't get an address of a rvalue type void
}

int main(){
  List list(8); 
  list.add(9);
  list.add(7);
  list.add(4);
  list.add(3);

  return 0;
}
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
wavesinaroom
  • 105
  • 8
  • 4
    Omit the `()` in `&func()` — the parentheses convert the reference into a function call. The `&` is unnecessary too, but mostly harmless. That is, either `iterate(node->next, &func);` or `iterate(node->next, func);` should work. Function pointers are slightly oddball. – Jonathan Leffler Mar 29 '23 at 03:13
  • Thanks a lot @JonathanLeffler! It definitely worked on my side. Can I ask you for any recommended article/tutorial/material I can read to understand more about callbacks? I'd like to understand why your suggestion works – wavesinaroom Mar 29 '23 at 03:32
  • 1
    I commend the use of what I would I consider an idiomatic approach to a linked list in C++. One point, The C-style declaration of the node struct should be chaanged. `struct Node { /* members here */ };` is all you need. – sweenish Mar 29 '23 at 03:45
  • 1
    If a variable `fp` has the type `pointer to function`, then using `fp(…)` (for an appropriate argument list, possibly an empty list) actually invokes the function, and the result is the return value (if any) from the function. However, a function name without a following argument list becomes a 'pointer to function'. You can also use `(fp)(…)` or `(*fp)(…)` to invoke the function. The former version invokes the function by name, even if there is a macro override. The second is the original notation used by pre-standard C. Standard C allows `fp(…)` but pre-standard C required `(*fp)(…)`. – Jonathan Leffler Mar 29 '23 at 03:47
  • 1
    Is there a reason you use your own list instead of [std::list](https://en.cppreference.com/w/cpp/container/list)? . Learning C++ is also about learning (re)use of tested library code. Side notes in C++ you can consider to use [std::function](https://en.cppreference.com/w/cpp/utility/functional/function) instead of function pointers, which will allow you to use [lambda functions](https://en.cppreference.com/w/cpp/language/lambda) (with captures) as parameter. – Pepijn Kramer Mar 29 '23 at 03:49
  • 2
    @PepijnKramer Writing a linked list from scratch is an **excellent** way to practice a lot of different principles at once. I wouldn't knock it. – sweenish Mar 29 '23 at 03:58
  • 1
    @sweenish I agree, my comment wasn't about knocking anyone down. My mode of thinking is more like if you want to test on callbacks only test that and use tested code for the rest. ;) – Pepijn Kramer Mar 29 '23 at 04:04
  • Hey @sweenish! Thanks for your suggestion. Could you expand on it? I declared the structure in that way according to a book I'm reading but it would be great to read why you recommended `struct Node{ /*members here*/}` – wavesinaroom Mar 30 '23 at 02:05
  • @JonathanLeffler awesome, makes total sense now. So, adding the parenthesis makes the difference between calling it and a 'pointer to function' (it reminds of javascript callbacks). Thanks for that :) – wavesinaroom Mar 30 '23 at 02:08
  • 1
    The book you're reading is out-of-date. There is simply nothing to expand upon. You are using the C-style method, my suggestion is idiomatic C++. – sweenish Mar 30 '23 at 02:11
  • @PepijnKramer I understand why you asked that, that's alright! When I learn something I always try to get good foundations even though doing that takes time. Recently, I finished a project on React.js that wouldn't have been so easy had I not had some practice (and headaches) working on a similar project with vanilla javascript. Certainly, I would use the standard library in a real work situation that's why I've planned to go into in detail in the future. – wavesinaroom Mar 30 '23 at 02:15
  • @sweenish gotcha, I'm gonna change that in my code. Thanks! – wavesinaroom Mar 30 '23 at 02:16

1 Answers1

1

As noted in comments, in the following you are not passing the function pointer, but rather the address of the result of calling that function.

void List::iterate(Node * node, void(*func)()){
  func();//prints or finds min 
  if(node->next == nullptr)
    return;
  iterate(node->next,&func()); //--compiler says it can't get an address of a > rvalue type void
}

Rather:

void List::iterate(Node * node, void(*func)()) {
  func();
  if(node->next == nullptr)
    return;
  iterate(node->next, func); 
}
Chris
  • 26,361
  • 5
  • 21
  • 42