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!
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.
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).
Related
I want to create a simple program that demonstrates the usage of this. I wrote a function that prints the x and y membervariables. I defined the function on top of the file. I acutally don't even know why that is needed but ok. So far so good. Visual Studio finds zero issues, no warnings and no erros. However when I compile this code I get the following error message:
1>D:\Dev\Visual Studio Projekte\Projektmappe\FirstProject\src\This.cpp(3,30): error C2143: syntax error: missing ',' before '*'
1>D:\Dev\Visual Studio Projekte\Projektmappe\FirstProject\src\This.cpp(11,1): error C2664: 'void PrintObject(const int)': cannot convert argument 1 from 'Object *' to 'const int'
Now at some point I also got the error that no default constructor is defined. However the compiler does provide one right? I then simply retyped the code and the error disappeared. Just something I wanted to mention that also seemed stupid.
So why is the compiler thinking that "this" is referring to a "const int" when it is in fact referring to my object?
#include <iostream>
void PrintObject(const Object* o);
class Object {
public:
int x, y;
Object(int x, int y)
: x(x), y(y) {
PrintObject(this);
}
int GetX() const {
return this->x;
}
int GetXy() const {
return x;
}
};
void PrintObject(const Object* o) {
std::cout << o->x << ", " << o->y << std::endl;
}
int main() {
std::cin.get();
return 0;
}
void PrintObject(const Object* o);
You haven't declared Object yet, so the compiler cannot know what it is. You must first declare the class before delaring this function. Technically, they can both be declared at the same time, but that isn't a very popular style.
I also got the error that no default constructor is defined. However the compiler does provide one right?
It does not provide one. Default constructor is only provided for classes with no user declared constructors (and no non-default constructible sub objects).
It's simple enough, you are using Object before you are declaring it. So the compiler doesn't know what Object is at the time it reads the declaration of PrintObject.
Two possible solutions.
1) Move the declaration of PrintObject after the definition of Object.
class Object
{
...
};
void PrintObject(const Object* o);
2) Use a forward declaration to tell the compiler that Object is the name of a class.
class Object; // forward declaration
void PrintObject(const Object* o);
class Object
{
...
};
PrintObject could be defined as a member function. Would make the syntax much nicer.
#include <iostream>
class Object {
public:
Object(int x, int y)
: x(x), y(y) {
PrintObject();
}
int GetX() const {
return this->x;
}
int GetXy() const {
return x;
}
void PrintObject() const {
std::cout << x << ", " << y << std::endl;
}
private:
int x, y;
};
int main() {
Object o{5,6};
return 0;
}
Also you might want to consider, overwriting the output stream operator, if you want to define custom print for your type.
I am trying to wrap my head around passing method as function argument. Here is a simplified example which returns a compilation error that I don't understand
class B
{
private:
int j;
public:
void foo(int i){std::cout << i + this->j << std::endl;}
void setj(int J){j=J;}
};
class A
{
private:
B b;
public:
void call(void (B::*fun)(int i), int i) { b.*fun(i); }
void setBj(int j){b.setj(j);}
};
int main()
{
A a;
a.setBj(40);
a.call(B::foo, 2);
}
When compiled with
g++ -std=c++11 b.cpp -o b
I get
b.cpp:22:50: error: called object type 'void (B::*)(int)' is not a function or
function pointer
void call(void (B::*fun)(int i), int i) { b.*fun(i); }
~~~^
b.cpp:31:12: error: call to non-static member function without an object
argument
a.call(B::foo, 2);
~~~^~~
2 errors generated.
I don't understand the first error message. I understand that I am calling foo as if it was a static method, which it is not but I don't understand how to pass a non-static method.
Two problems.
To invoke a pointer to a member function, you need to first apply a pointer to member access operator, that obtains a callable expression. Then you add a call. Now it just so happens that .* is of lower precedence than the function call operator. So the first fix:
(b.*fun)(i)
A a pointer to member function can only be obtained by applying unary & on the fully qualified function name. So the second fix:
a.call(&B::foo, 2);
I'm trying call a method initialised by pointer to a method of other class, i've followed this:
but it has not worked for me.
consider this:
class y
{
public:
int GetValue(int z)
{
return 4 * z;
}
};
class hooky
{
public:
int(hooky::*HookGetValue)(int);
};
int(hooky::*HookGetValue)(int) = (int(hooky::*)(int))0x0; // memory address or &y::GetValue;
int main()
{
hooky h; // instance
cout << h.*HookGetValue(4) << endl; // error
return 0;
}
the error that produces is:
[Error] must use '.' or '->' to call pointer-to-member function in
'HookGetValue (...)', e.g. '(... ->* HookGetValue) (...)'
The correct syntax to invoke a member function pointer is
(h.*HookGetValue)(4)
Update: the reason original code does not work as expected is because of operator precedence of C++: function invocation () is having higher precedence than ptr to member .*. Which means
h.*HookGetValue(4)
will be see as
h.*(HookGetValue(4))
code:
#include <iostream>
using namespace std;
struct item
{
int f1() {}
double f2() {}
static int g1() {}
static double g2() {}
void f0();
};
void item::f0()
{
auto c1 = reinterpret_cast<decltype(f2)>(f1);
auto c2 = reinterpret_cast<decltype(g2)>(g1);
auto c3 = reinterpret_cast<decltype(&f2)>(f1);
auto c4 = reinterpret_cast<decltype(&g2)>(g1);
}
int main()
{
cout << "Hello world!" << endl;
return 0;
}
error message:
main.cpp|17|error: invalid use of non-static member function|
main.cpp|18|error: invalid cast from type ‘int (*)()’ to type ‘double()’|
main.cpp|20|error: ISO C++ forbids taking the address of an unqualified or parenthesized non-static member function to form a pointer to member function. Say ‘&item::f2’ [-fpermissive]|
main.cpp|20|error: invalid use of member function (did you forget the ‘()’ ?)
my question:
The member functions passed as arguments will automatically convert to pointer, so i try casting the argument to a pointer, but still failed.
I don't understand why non-static member function doesn't work in all
situation.
You need to cast the return value of f1, not f1. Use:
auto c1 = reinterpret_cast<decltype(f2())>(f1());
^^ Call the function
Make similar changes to the other lines.
I misunderstood what you were trying to do. The following should work:
auto c1 = reinterpret_cast<decltype(&item::f2)>(&item::f1);
auto c2 = reinterpret_cast<decltype(&g2)>(g1);
auto c3 = reinterpret_cast<decltype(&item::f2)>(&item::f1);
auto c4 = reinterpret_cast<decltype(&g1)>(g2);
f1 is a non-staticmember function. You can call it using f1(). However, without the function call syntax, non-static member functions don't automatically decay to a member function pointer. To get a member function pointer of the struct, you'll need to use &item::f1.
class A {
int f(int x, int j) { return 2;}
decltype(f)* p;
};
Gives me the error:
error: decltype cannot resolve address of overloaded function
I can't understand why that error is even speaking of overloaded functions. Similarly I thought that maybe I needed to use the scope operator to access the function:
class A {
int f(int x, int j) { return 2;}
decltype(A::f)* p;
};
Which still gives me an error but a clearer description:
error: invalid use of non-static member function 'int A::f(int, int)'
Why is it that I'm not allowed to use decltype to find the type of a member function? Alternatively setting the member function to static removes the error in either case.
What you really want is:
struct a {
int f(int x, int j) { return 2;}
decltype(&a::f) p;
};
Live demo
Since the f you are referring to is a member function. The deduced type is:
int(a::*)(int, int)
Without the & the compiler is assuming that you are trying to call the function without providing arguments to it. Perhaps Clang's error message is clearer about this:
error: call to non-static member function without an object argument
decltype(a::f) p;
If you really don't want the pointer type you can later apply std::remove_pointer_t from <type_traits>.