0

I am trying to define a class named RationalNumber. In the constructor I want to simplify the fraction represented by the RationalNumber using a callback function to another function (named simplification), but I receive some errors and I can't figure out what I am missing.

The first error is cannot convert from 'void (__cdecl *)(RationalNumber &)' to 'RationalNumber::pointer_to_f' Prob2 ...\source\repos\Prob2\Prob2\NumarRational.h 21

#pragma once
#include <iostream>
using namespace std;

class RationalNumber {
    typedef void (RationalNumber::*pointer_to_f)(RationalNumber&);
private:
    int a;
    int b;

    void callback(pointer_to_f);
    static int gcd(int, int);
public:
    RationalNumber(int = 0, int = 0);
    static void simplification(RationalNumber&);
};

RationalNumber::RationalNumber(int x, int y) {
    this->a = x;
    this->b = y;
    pointer_to_f p = &simplification;    // <-- line 21, location of the first error
    callback((p)(this));

}

int RationalNumber::gcd(int a, int b)
{
    if (b == 0)
        return a;
    return gcd(b, a % b);
}

void RationalNumber::simplification(RationalNumber& x) {
    int d = gcd(x.a, x.b);
    if (d != 1) {
        x.a /= d;
        x.b /= d;
    }
}

void RationalNumber::callback(pointer_to_f *p(RationalNumber& x) ) {
    (*p)(x);
 }

The full error log:

Error   C2440   'initializing': cannot convert from 'void (__cdecl *)(RationalNumber &)' to 'RationalNumber::pointer_to_f'  Prob2   ...\source\repos\Prob2\Prob2\NumarRational.h    21

Error   C2511   'void RationalNumber::callback(RationalNumber::pointer_to_f *(__cdecl *)(RationalNumber &))': overloaded member function not found in 'RationalNumber'  Prob2   ...\source\repos\Prob2\Prob2\NumarRational.h    39

Error   C2065   'x': undeclared identifier  Prob2   ...\source\repos\Prob2\Prob2\NumarRational.h    40  

Error (active)  E0144   a value of type "void (*)(RationalNumber &x)" cannot be used to initialize an entity of type "RationalNumber::pointer_to_f" Prob2   ...\source\repos\Prob2\Prob2\NumarRational.h    21  

Error (active)  E0147   declaration is incompatible with "void RationalNumber::callback(RationalNumber::pointer_to_f)" (declared at line 11 of "...\source\repos\Prob2\Prob2\NumarRational.h")  Prob2   ...\source\repos\Prob2\Prob2\NumarRational.h    39  

Error (active)  E0109   expression preceding parentheses of apparent call must have (pointer-to-) function type Prob2   ...\source\repos\Prob2\Prob2\NumarRational.h    22

Error (active)  E0020   identifier "x" is undefined Prob2   ...\source\repos\Prob2\Prob2\NumarRational.h    40  

Error   C2064   term does not evaluate to a function taking 1 arguments Prob2   ....source\repos\Prob2\Prob2\NumarRational.h    22  

Thank you!

JaMiT
  • 14,422
  • 4
  • 15
  • 31

2 Answers2

0

cannot convert from 'void (__cdecl *)(RationalNumber &)' to 'RationalNumber::pointer_to_f'

on the line

pointer_to_f p = &simplification;

Let's see what we have here. This line initializes a variable (p) of type RationalNumber::pointer_to_f, which corresponds with what the attempted conversion is to. On the right-hand side of the = is the address of RationalNumber::simplification, a static member function from RationalNumber& to void. Check, that matches the error message.

So the first error comes down to the fact that a pointer to member function must point to a non-static member function. The address of a static member function is a normal function pointer (largely because it lacks the hidden this parameter).

Given your setup, it seems to make sense to remove the static keyword from simplification as well as removing its parameter. Have it operate on *this, which becomes available once the member function is no longer static.

Alternatively, you could change your pointers to member functions into regular pointers to functions, if for some reason simplification needs to be static. (Given that the function needs a RationalNumber object in either case, I don't see why static would be desirable.)


The remaining errors are technically independent, but I'll throw in some that have to do with invalid use of a pointer to member function.

callback((p)(this));

This invokes the function pointed to by p and supplies the pointer this as an argument. The returned value (void) becomes the argument to callback. If you want to pass p as the argument to callback, then pass p:

callback(p);

void RationalNumber::callback(pointer_to_f *p(RationalNumber& x) )

This does not match the declaration. You declared callback as a function whose parameter is a pointer_to_f. This definition has a parameter whose type is a function taking a RationalNumber& parameter and returning a pointer_to_f (the x is meaningless here). Be consistent!

void RationalNumber::callback(pointer_to_f p)

If you want to pass in something to use as the argument when p is invoked, you would need a second parameter. See also Function pointer to member function for how to fix the syntax you use to invoke p.


Final note: using a callback here looks like serious over-engineering, but I suppose the need for it might exist in details removed to make the example code simple.

JaMiT
  • 14,422
  • 4
  • 15
  • 31
-1

The bellow modified code compiles and shows how to use a static method as a "callback" but as stated above it si not clear why you do not want to directly use simplification method from the constructor (instead of using a pointer of this method)

 #include <functional>
class RationalNumber {

            private:
                int a;
                int b;


                static int gcd(int, int);
            public:
                RationalNumber(int = 0, int = 0);
                static void simplification(RationalNumber&);


            };

            RationalNumber::RationalNumber(int x, int y) {
                this->a = x;
                this->b = y;
                std::function<void(RationalNumber&)> p= &RationalNumber::simplification;
                p(*this) ;

            }
            int RationalNumber::gcd(int a, int b)
            {
                if (b == 0)
                    return a;
                return gcd(b, a % b);

            }
            void RationalNumber::simplification(RationalNumber& x) {
                int d = gcd(x.a, x.b);
                if (d != 1) {
                    x.a /= d;
                    x.b /= d;
                }
            }

Function pointers need to be static (cannot be object methods). So in the above sample you could declare gcd and simplification as standard function (not object methods).

Jean-Marc Volle
  • 3,113
  • 1
  • 16
  • 20
  • 1
    Yes, it might be possible to redesign the interface to get rid of this coding error. That's backwards: fix the coding error. Adding the overhead of `std::function` is one way to fix the coding error, but it's much better to simply write the function call correctly. – Pete Becker May 16 '20 at 15:00
  • your last paragraph is wrong. There are pointers to non-static member functions, you just cannot use them to call the method without an instance. – 463035818_is_not_an_ai May 16 '20 at 15:19
  • Hello @idclev463035818. Do you have an example of using a object method directly as a callback? – Jean-Marc Volle May 16 '20 at 15:46