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.
Related
I've got some problem using std::function
It works with static int funcAB but, in reality, I need std function for non-static in class.
#include <functional>
#include <iostream>
class test{
public:
std::function<int (int, int)> func;
int funcAB(int a, int b){
return a + b;
}
test(){
func = test::funcAB;
}
};
int main(){
using namespace std;
test A;
cout <<A.funcAB(10,11) << endl;
cout <<A.func(11,12) << endl;
}
Error:
main.cpp:11:22: error: invalid use of non-static member function ‘int test::funcAB(int, int)’
func = test::funcAB;
^~~~~~
There are two problems here:
The first is that to get a pointer to a member function you need to use the address-of operator &. As in &test::funcAB.
The other problem is that non-static member functions needs an object to be called on. If you don't have an object, you can't call it.
To solve the second problem either use std::bind
using namespace std::placeholders; // for _1, _2, _3...
func = std::bind(&test::funcAB, this, _1, _2);
Or use a lambda
func = [this](int a, int b)
{
return funcAB(a, b);
};
Lambdas are generally recommended over std::bind.
Pointer to non-static member functions are different, you have to invoke them with the first argument being an instance of the particular object that the member function shall be associated with. In your case, you can fix this by first correctly declaring and assigning to func:
std::function<int (test&, int, int)> func;
// ...
func = &test::funcAB;
Then, the call side looks a bit different, too. Pass A as the first parameter here:
cout <<A.func(A,11,12) << endl;
Note that there is a different solution. You can leave the func declaration as it is and assign a lambda to it that captures this:
func = [this](int a, int b){ return funcAB(a, b); };
I am trying to pass a function as an argument to a template class - the objective is that then I can pass any function as a argument and achieve different functionality:
int A()
{
return 0;
}
void Test() {
auto B2 = B<int(*A)()>(&A);
}
int main()
{
Test();
}
But I am getting compilation issue:
$ c++ -std=c++14 try.cpp
try.cpp: In function 'void Test()':
error: cast from 'int (*)()' to 'int' loses precision [-fpermissive]
auto B2 = B<int(*A)()>(&A);
^ ^
How can I instantiate class B with a function of any return type and accepting any argument and resolve the compilation?
You should remove the function name A in the template parameter in the line auto B2 = ... such that it looks like this:
auto B2 = B<int(*)()>(A);
The name is not a part of the type specifier, and the type is the only thing the compiler looks for when trying to instantiate the class template. You can use this snippet to refer to the name of the function and let the compiler deduce its type:
auto B2 = B<decltype(&A)>(A);
Note that you can optionally drop the & before A when passing it to the constructor of B (doesn't work for decltype(&A) though), as it's implicitly converted to a function pointer.
Function name is not part of the type of a function pointer.
This line:
auto B2 = B<int(*A)()>(&A);
should be:
auto B2 = B<int(*)()>(&A);
struct A
{
void f() {}
};
void f() {}
int main()
{
auto p1 = &f; // ok
auto p2 = f; // ok
auto p3 = &A::f; // ok
//
// error : call to non-static member function
// without an object argument
//
auto p4 = A::f; // Why not ok?
}
Why must I use address-of operator to get a pointer to a member function?
auto p1 = &f; // ok
auto p2 = f; // ok
The first is more or less the right thing. But because non-member functions have implicit conversions to pointers, the & isn't necessary. C++ makes that conversion, same applies to static member functions.
To quote from cppreference:
An lvalue of function type T can be implicitly converted to a prvalue
pointer to that function. This does not apply to non-static member
functions because lvalues that refer to non-static member functions do
not exist.
I'm having trouble understanding function signatures and pointers.
struct myStruct
{
static void staticFunc(){};
void nonstaticFunc(){};
};
int main()
{
void (*p)(); // Pointer to function with signature void();
p = &myStruct::staticFunc; // Works fine
p = &myStruct::nonstaticFunc; // Type mismatch
}
My compiler says that the type of myStruct::nonstaticFunc() is void (myStruct::*)(), but isn't that the type of a pointer pointing to it?
I'm asking because when you create an std::function object you pass the function signature of the function you want it to point to, like:
std::function<void()> funcPtr; // Pointer to function with signature void()
not
std::function<void(*)()> funcPtr;
If I had to guess based on the pattern of void() I would say:
void myStruct::();
or
void (myStruct::)();
But this isn't right. I don't see why I should add an asterisk just because it's nonstatic as opposed to static. In other words, pointer void(* )() points to function with signature void(), and pointer void(myStruct::*)() points to function with signature what?
To me there seems to be a basic misunderstanding of what a member pointer is. For example if you have:
struct P2d {
double x, y;
};
the member pointer double P2d::*mp = &P2d::x; cannot point to the x coordinate of a specific P2d instance, it is instead a "pointer" to the name x: to get the double you will need to provide the P2d instance you're looking for... for example:
P2d p{10, 20};
printf("%.18g\n", p.*mp); // prints 10
The same applies to member functions... for example:
struct P2d {
double x, y;
double len() const {
return sqrt(x*x + y*y);
}
};
double (P2d::*f)() const = &P2d::len;
where f is not a pointer to a member function of a specific instance and it needs a this to be called with
printf("%.18g\n", (p.*f)());
f in other words is simply a "selector" of which of the const member functions of class P2d accepting no parameters and returning a double you are interested in. In this specific case (since there is only one member function compatible) such a selector could be stored using zero bits (the only possible value you can set that pointer to is &P2d::len).
Please don't feel ashamed for not understanding member pointers at first. They're indeed sort of "strange" and not many C++ programmers understand them.
To be honest they're also not really that useful: what is needed most often is instead a pointer to a method of a specific instance.
C++11 provides that with std::function wrapper and lambdas:
std::function<double()> g = [&](){ return p.len(); };
printf("%.18g\n", g()); // calls .len() on instance p
std::function<void()> funcPtr = std::bind(&myStruct::nonstaticFunc, obj);
Is how you store a member function in std::function. The member function must be called on a valid object.
If you want to delay the passing of an object until later, you can accomplish it like this:
#include <functional>
#include <iostream>
struct A {
void foo() { std::cout << "A::foo\n"; }
};
int main() {
using namespace std::placeholders;
std::function<void(A&)> f = std::bind(&A::foo, _1);
A a;
f(a);
return 0;
}
std::bind will take care of the details for you. std::function still must have the signature of a regular function as it's type parameter. But it can mask a member, if the object is made to appear as a parameter to the function.
Addenum:
For assigning into std::function, you don't even need std::bind for late binding of the object, so long as the prototype is correct:
std::function<void(A&)> f = &A::foo;
p = &myStruct::staticFunc; // Works fine
p = &myStruct::nonstaticFunc; // Type mismatch
Reason : A function-to-pointer conversion never applies to non-static member functions because an lvalue that refers to a non-static member function
cannot be obtained.
pointer void(* )() points to function with signature void(), and pointer void(myStruct::*)() points to function with signature what?
myStruct:: is to make sure that the non-static member function of struct myStruct is called (not of other structs, as shown below) :
struct myStruct
{
static void staticFunc(){};
void nonstaticFunc(){};
};
struct myStruct2
{
static void staticFunc(){};
void nonstaticFunc(){};
};
int main()
{
void (*p)(); // Pointer to function with signature void();
void (myStruct::*f)();
p = &myStruct::staticFunc; // Works fine
p = &myStruct2::staticFunc; // Works fine
f = &myStruct::nonstaticFunc; // Works fine
//f = &myStruct2::nonstaticFunc; // Error. Cannot convert 'void (myStruct2::*)()' to 'void (myStruct::*)()' in assignment
return 0;
}
When you use a pointer, std::function or std::bind to refer to a non-static member function (namely, "method" of class Foo), the first param must be a concrete object of class Foo, because non-static method must be called by a concrete object, not by Class.
More details: std::function and
std::bind.
The answer is in the doc.
Pointer to member declarator: the declaration S C::* D; declares D as
a pointer to non-static member of C of type determined by
decl-specifier-seq S.
struct C
{
void f(int n) { std::cout << n << '\n'; }
};
int main()
{
void (C::* p)(int) = &C::f; // pointer to member function f of class C
C c;
(c.*p)(1); // prints 1
C* cp = &c;
(cp->*p)(2); // prints 2
}
There are no function with signature void (). There are void (*)() for a function or void (foo::*)() for a method of foo. The asterisk is mandatory because it's a pointer to x. std::function has nothing to do with that.
Note: Your confusion is that void() is that same signature that void (*)(). Or even int() <=> int (*)(). Maybe you think that you can write int (foo::*) to have a method pointer. But this is a data member pointer because the parenthesis are optional, int (foo::*) <=> int foo::*.
To avoid such obscure syntax you need to write your pointer to function/member with the return type, the asterisk and his parameters.
When returning a member function pointer to a class within one of that class's member functions I still have to specify the class. I cannot simply take the address. For example, this code works fine:
class Foo {
public:
void func(int param) { cout << param << endl; }
void (Foo::*getPointer())(int) { return &Foo::func; }
};
But if in getPointer I try to simply do: return &func I get this error:
prog.cpp: In member function 'void (Foo::* Foo::getPointer())(int)':
prog.cpp:8:43: error: ISO C++ forbids taking the address of an unqualified or parenthesized non-static member function to form a pointer to member function. Say '&Foo::func' [-fpermissive]
void (Foo::*getPointer())(int) { return &func; }
Why must I specify the class when that's the context that I am within?
Pointers and pointer to members are distinct types, we can see that from section the draft C++ standard section 3.9.2 [basic.compound] which includes a compound type for pointer as well as pointer to non-static class member and notes:
Static class members are objects or functions, and pointers to them
are ordinary pointers to objects or functions
This issue with this is I think well described in this quote in an answer from Johannes from the Annotated C++ Reference Manual(ARM):
Note that the address-of operator must be explicitly used to get a
pointer to member; there is no implicit conversion ... Had there been,
we would have an ambiguity in the context of a member function ... For
example,
void B::f() {
int B::* p = &B::i; // ok
p = B::i; // error: B::i is an int
p = &i; // error: '&i'means '&this->i'
// which is an 'int*'
int *q = &i; // ok
q = B::i; // error: 'B::i is an int
q = &B::i; // error: '&B::i' is an 'int B::*'
}
In particular these lines:
int B::* p = &B::i; // OK
and:
p = &i; // error: '&i'means '&this->i' which is an 'int*'
demonstrate the difference between the qualified and the unqualified name.
(...there was a wrong answer...)
It looks more strange in the following context:
class Foo {
public:
virtual void func(int param) { cout << param << endl; }
void call(int x) { Foo::func(x); }
void (Foo::*getPointer())(int) { return &Foo::func; }
};
class Bar : public Foo {
public:
void func(int param) override { cout << "Hello world!" << endl; }
};
int main() {
Foo *a = new Bar();
auto p = a->getPointer();
(a->*p)(4);
a->call(4);
return 0;
}
The output is
Hello world
4
Calling Foo::func is a call of func in Foo class while calling &Foo::func is a virtual call.