0

As the title asks, I find myself unable to implement a straightforward (ha) callback function in C++.

Now if you're thinking "I'm sure I've seen a question/answer for that before", you're absolutely correct, namely: Callback functions in c++

The reason I am posting anew is that I cannot get anything to work. I've tried applying the 1st answer that I fully understand [1], directly to my code; but I get 30 errors.

The first problem of these 30 errors, I don't understand. It's relating to the typedef declaration:

  typedef std::tr1::function<int (const GameCharacter&)> HealthCalcFunc;

It appears that 'tr1' is missing:

..\..gLib\..sor.h(47) : error C2039: 'function' : is not a member of 'std::tr1'

The following errors are reminiscent of a missing ';' gone missing or similar:

..\..gLib\..sor.h(47) : error C2143: syntax error : missing ';' before '<'
..\..gLib\..sor.h(47) : error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
..\..gLib\..sor.h(47) : error C2238: unexpected token(s) preceding ';'
..\..gLib\..sor.h(51) : error C2061: syntax error : identifier 'DataProcessorFunc'
..\..gLib\..sor.h(104) : error C2146: syntax error : missing ';' before identifier 'callbackFunc'

Moving down the page, there is another answer [2] that appears even more obvious. So I've created a fresh project with these two classes but again the errors beat me; I find myself unable to progress.

...\gamecharactertest\class1.h(17) : error C2146: syntax error : missing ';' before identifier 'F1'
    ...\gamecharactertest\class1.h(17) : error C2182: 'CALLBACK' : illegal use of type 'void'
jom:    ...\GameCharacterTest\Makefile.Release [release\class1.obj] Error 2
    ...\gamecharactertest\class1.h(17) : error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
    ...\gamecharactertest\class1.h(17) : warning C4183: 'F1': missing return type; assumed to be a member function returning 'int'
    ...\gamecharactertest\class1.h(19) : error C2143: syntax error : missing ':' before '}'
class1.cpp(11) : error C2143: syntax error : missing ';' before 'C1::F1'
class1.cpp(11) : error C2182: 'CALLBACK' : illegal use of type 'void'
class1.cpp(12) : error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
    [...]
    ...\gamecharactertest\class2.h(16) : error C2143: syntax error : missing ')' before '<tag>::*'
    ...\gamecharactertest\class2.h(16) : error C2657: 'C1::*' found at the start of a statement (did you forget to specify a type?)
    ...\gamecharactertest\class2.h(16) : error C2059: syntax error : ')'
    ...\gamecharactertest\class2.h(16) : error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
    ...\gamecharactertest\class2.h(16) : warning C4183: 'pfnCallBack': missing return type; assumed to be a member function returning 'int'
    ...\gamecharactertest\class2.h(21) : error C2061: syntax error : identifier 'pfnCallBack'
class2.cpp(10) : error C2061: syntax error : identifier 'pfnCallBack'
class2.cpp(14) : error C2065: 'pFn' : undeclared identifier

If someone could be so kind as to point out where I have screwed up, I would be eternally grateful. Many thanks in advance.

[1] https://stackoverflow.com/a/2298291/2903608

[2] https://stackoverflow.com/a/24899454/2903608

--------------------- Edit --------------------

I have amended my question and I'm adding this in reply to this skyking's reply. It's very good, I think I'm just failing at the final hurdle though.

I have a header file (class1.h) containing "class A" as illustrated in his reply:

#ifndef CLASS1_H
#define CLASS1_H

#include <QCoreApplication>

class A {
    void callback(int value) {
        printf("callback: got %d\n", value);
    }
};
#endif // CLASS1_H

and its associated (class1.cpp) containing its sole method:

#include "class1.h"

void do_something(int value, A* obj, void (A::*cb)(int)) {
    (obj->*cb)(value);
}

and in my file (mainly.cpp) I've placed the function definitions and the main function:

#include <QCoreApplication>
#include "class1.h"

using namespace std;

void callback(int value) {
     printf("callback: got %d\n", value);
}

void do_something(int value, void (*cb)(int)) {
     // do something
     cb(value); // call the callback
}

void do_anotherthing(int value, std::function<void(int)> const& cb) {
    cb(value);
}

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    A theA = A();
    do_anotherthing(45, theA.callback);

    // Original exercise, works fine
    do_something(42, callback);
    return a.exec();
}

So when I do the initial step, calling do_something(..) that works fine. But the final step fails. Noted that to avoid confusions over names, I have renamed skyking's two last definition of do_something() to be called to do_anotherthing(). However, I have the following errors which I don't know how to sort out:

main.cpp(15) : error C2039: 'function' : is not a member of 'std'
main.cpp(15) : error C2061: syntax error : identifier 'function'
main.cpp(16) : error C3861: 'cb': identifier not found

main.cpp(24) : error C3867: 'A::callback': function call missing argument list; use '&A::callback' to create a pointer to member
main.cpp(24) : error C2660: 'do_anotherthing' : function does not take 2 arguments

Finally, I would just like to take a moment to express my immense gratitude for the knowledge and speed of the replies on the occasions I needed to post a question here at SO. Thank you all very much indeed.

Community
  • 1
  • 1
PhilPhil
  • 173
  • 4
  • 18
  • 6
    The `std::tr1` namespace was just experimental while the C++11 specification was developed, it's obsolete now. Use [`std::function`](http://en.cppreference.com/w/cpp/utility/functional/function) instead. – Some programmer dude Oct 26 '15 at 12:11
  • Recommended reading: http://stackoverflow.com/questions/4682919/what-are-differences-between-std-tr1-and-boost-as-namespaces-and-or-libraries – Christian Hackl Oct 26 '15 at 12:30
  • @JoachimPileborg Thanks! I tried `typedef std::/*tr1::*/function<..`but unfortunately get `'function' : is not a member of 'std' `.. @skyking: Thanks for the detailed walk-through, I shouldn't be able to go wrong with that (fingers crossed). – PhilPhil Oct 26 '15 at 13:06

1 Answers1

5

I think one could question the claim that you fully understand the answer(s).

To get an understanding of it I think you should probably start in the right end of the problem by cutting away all the bells-and-whistles that distracts from the core issue. Let's start with a plain C-ish solution:

void callback(int value) {
     printf("callback: got %d\n", value);
}

void do_something(int value, void (*cb)(int)) {
     // do something
     cb(value); // call the callback
}

int main() {
    do_something(42, callback);
    return 0;
}

nothing fancy - the callback is simply a pointer to a function that is then called.

Next step is maybe to watch what happens if you want to pass a method to do_something instead of a plain vanilla function. It will fail because a method is not of the same type as a function (because they cannot be used the same way, a method needs an object to be called while a function doesn't). This means that you would have to use a pointer to member of (a) class instead:

class A {
    void callback(int value) {
        printf("callback: got %d\n", value);
    }
};

void do_something(int value, A* obj, void (A::*cb)(int)) {
    (obj->*cb)(value);
}

However this has the problem that you have restricted youself to having a method of class A as the callback - you couldn't no longer use a plain function as callback. Here std::function comes to the rescue since it uses a wrapper that can wrap any kind of callables in a single object

void do_something(int value, std::function<void(int)> const& cb) {
    cb(value);
}

then you can call it with any kind of callbacks.

skyking
  • 13,817
  • 1
  • 35
  • 57
  • **skyking**: Thank you for the detailed explanations, just what I needed. However, I still fall foul of std::function apparently not existing. I'll edit my question to illustrate. – PhilPhil Oct 26 '15 at 15:45
  • @PhilPhil Did you remove the `tr1` namespace? And did you `#include `? – skyking Oct 26 '15 at 18:37
  • Aha, I did not know that there was a `` library out there. Including that in my code has greatly reduced the number of errors. Thank you! – PhilPhil Oct 27 '15 at 09:31
  • Unfortunately, I cannot figure out how to call `do_something` in the 3rd snippet. Namely, how to resolve the second argument (`&cb`). While I think your answer matches my question, I realise my question no longer matches my problem (having consulted with my boss). So I'll mark your answer is correct and go back to the textbooks. Thank you for your knowledge and patience. – PhilPhil Oct 27 '15 at 13:20