What's the function signature of a member function? - c++

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.

Related

Why is there only pointer to function instead of var of function?

In C/C++, we can declare/define a type of pointer to function, and then declare/define some variables of this type.
But I think it is ambiguity.
For example:
typedef void ( *pFunc )();
// typedef void ( aFunc )();
void theFunc() {
cout << "theFunc has been called successfully." << endl;
};
int main() {
pFunc pf0 = theFunc;
pFunc pf1 = &theFunc;
pf0();
( *pf0 )();
pf1();
( *pf1 )();
};
Theoretically, only pFunc pf1 = &theFunc; and (*pf1)(); are legal, but all of above can pass through compilation.
In Pascal syntax, we need to define vars of function or vars of pointer to a function respectively, and the meaning of them are different and much clearer(at least I think so)!
Moreover, we can't declare/define a var of function instead of a var of pointer to function!
I tried follows and get failed.
typedef void ( aFunc )();
aFunc af0 = theFunc;
If with other types such as int/double, there are very strict syntax that restricts us to use them correctly. (If int* is not same as int, why is *pf0 is same as pf0?!)
So, Can I think it is a bug of C/C++ standard?
Some declared types:
// decltype of theFunc is void ()
// decltype of &theFunc is void (*) ()
// decltype of *theFunc is void (&) ()
Now, concerning your code, since a function is implicitly convertible to a pointer to that function, we have:
using pFunc = void(*)();
using rFunc = void(&)();
pFunc p_fct = &theFunc; // no conversion
pFunc p_fct = theFunc; // conversion lvalue to pointer
pFunc p_fct = *theFunc; // conversion lvalue reference to pointer
rFunc r_fct = *theFunc; // no conversion
rFunc r_fct = theFunc; // conversion lvalue to lvalue reference
rFunc r_fct = &theFunc; // ERROR: conversion pointer to lvalue reference not allowed
So far the conversions. Now, any object of type pFunc or rFunc is a callable object. Also, note that both (*p_fct) and (*r_fct) are of type rFunc. Therefore, you can call your function as described in the question:
p_fct(); // callable object of type pFunc
r_fct(); // callable object of type rFunc
(*p_fct)(); // callable object of type rFunc
(*r_fct)(); // callable object of type rFunc
Note that the following is equivalent to the above:
using Func = void ();
Func* p_fct = &theFunc; // no conversion
Func& r_fct = *theFunc; // no conversion
p_fct(); // callable of type Func* or pFunc
r_fct(); // callablel of type Func& or rFunc
EDIT To answer to the question: "why them was arranged in this way" from the below comment: functions cannot be copied (as explained in #JohnBurger's answer). This is why your code:
typedef void ( aFunc )();
aFunc af0 = theFunc;
doesn't work. As explained above, you can do the following though:
typedef void ( aFunc )();
aFunc* af0 = &theFunc; // or theFunc, or even *theFunc
Or you could do this:
auto myFct = theFunc;
But keep in mind that the decltype of myFct is still void (*)().
Ignore functions for a second: think about a struct.
You can have a struct, or a pointer to a struct:
typedef struct {
int x;
int y;
} Point;
Point origin = { 0, 0 };
Point here = { 1, 1 };
Point there = { 2, 2 };
int main() {
Point centre = origin;
Point *myPoint = &origin;
centre = here;
myPoint = &here;
centre = there;
myPoint = &there;
} // main()
There are three global Points: origin, here and there.
main() has two variables: centre and myPoint.
centre copies the value of origin, here, and there.
myPoint points to origin, here, and there - it does not copy them.
There is a large difference between these two ideas: one copies the whole object, while the other only points to the other object.
Now think about functions. Functions are defined by the compiler in code, and can never be copied. So it makes no sense to have function variables - how large would they be? The only sensible idea is a pointer-to-function - so that is all that the C language provides.
If you want to define a C function typedef, use the following syntax:
// Fn is a function that accepts a char and returns an int
int Fn(char c);
// FnType is the type of a function that accepts a char and returns an int
typedef int FnType(char c);
// Here is the definition of Fn
int Fn(char c) {
return c + 1;
} // Fn(c)
// Now here is how you can use FnType
int main() {
FnType *fn = &Fn;
return fn('A');
} // main()
I think that I have found the answer.
Indeed c++ standard has offered a method to declare a type of function without the help of pointers.
example:
#include <functional>
using AFunc_t = function<void( int )>;
void theFunc( int );
AFunc_t afunc = theFunc;
I hope this could help someone.

compile error about template deduction on c++

#include <iostream>
template <int N>
class X {
public:
using I = int;
void f(I i) {
std::cout << "i: " << i << std::endl;
}
};
template <int N>
void fppm(void (X<N>::*p)(typename X<N>::I)) {
p(0);
}
int main() {
fppm(&X<33>::f);
return 0;
}
I just don't understand the compile error message of the code.
error: called object type 'void (X<33>::*)(typename X<33>::I)' is not a function or function pointer
p(0);
I think p is a function which returns void and takes int as its argument. But apparently, it's not. Could somebody give me clue?
Since p is a pointer to a nonstatic member function, you need an instance to call it with. Thus, first instantiate an object of X<33> in main:
int main() {
X<33> x;
fppm(x, &X<33>::f); // <-- Signature changed below to accept an instance
Then in your function, change the code to accept an instance of X<N> and call the member function for it:
template <int N>
void fppm(X<N> instance, void (X<N>::*p)(typename X<N>::I)) {
(instance.*p)(0);
}
The syntax may look ugly but the low precedence of the pointer to member operator requires the need for the parentheses.
As denoted in the comments already, p is a pointer to member function, but you call it like a static function (p(0);). You need a concrete object to call p on:
X<N> x;
(x.*p)(0);
// or:
X<N>* xx = new X<N>();
(xx->*p)(0);
delete xx;
Be aware that the .*/->* operators have lower precedence than the function call operator, thus you need the parentheses.
Side note: Above is for better illustration, modern C++ might use auto keyword and smart pointers instead, which could look like this:
auto x = std::make_unique<X<N>>();
(x.get()->*p)(0);

C++ Function call via an object with public member pointer to function, without using dereference operator

Alright, I think the title is sufficiently descriptive (yet confusing, sorry).
I'm reading this library: Timer1.
In the header file there is a public member pointer to a function as follows:
class TimerOne
{
public:
void (*isrCallback)(); // C-style ptr to `void(void)` function
};
There exists an instantiated object of the TimerOne class, called "Timer1".
Timer1 calls the function as follows:
Timer1.isrCallback();
How is this correct? I am familiar with calling functions via function pointers by using the dereference operator.
Ex:
(*myFunc)();
So I would have expected the above call via the object to be something more like:
(*Timer1.isrCallback)();
So, what are the acceptable options for calling functions via function pointers, as both stand-alone function pointers and members of an object?
See also:
[very useful!] Typedef function pointer?
Summary of the answer:
These are all valid and fine ways to call a function pointer:
myFuncPtr();
(*myFuncPtr)();
(**myFuncPtr)();
(***myFuncPtr)();
// etc.
(**********************************f)(); // also valid
Things you can do with a function pointer.
1: The first is calling the function via explicit dereference:
int myfunc(int n)
{
}
int (*myfptr)(int) = myfunc;
(*myfptr)(nValue); // call function myfunc(nValue) through myfptr.
2: The second way is via implicit dereference:
int myfunc(int n)
{
}
int (*myfptr)(int) = myfunc;
myfptr(nValue); // call function myfunc(nValue) through myfptr.
As you can see, the implicit dereference method looks just like a normal function call -- which is what you’d expect, since function are simply implicitly convertible to function pointers!!
In your code:
void foo()
{
cout << "hi" << endl;
}
class TimerOne
{
public:
void(*isrCallback)();
};
int main()
{
TimerOne Timer1;
Timer1.isrCallback = &foo; //Assigning the address
//Timer1.isrCallback = foo; //We could use this statement as well, it simply proves function are simply implicitly convertible to function pointers. Just like arrays decay to pointer.
Timer1.isrCallback(); //Implicit dereference
(*Timer1.isrCallback)(); //Explicit dereference
return 0;
}
You don't have to dereference a function pointer to call it. According to the standard ([expr.call]/1),
The postfix expression shall have
function type or pointer to function type.
So (*myFunc)() is valid, and so is myFunc(). In fact, (**myFunc)() is valid too, and you can dereference as many times as you want (can you figure out why?)
You asked:
Timer1 calls the function as follows:
Timer1.isrCallback();
How is this correct?
The type of Timer1.isrCallback is void (*)(). It is a pointer to a function. That's why you can use that syntax.
It is similar to using:
void foo()
{
}
void test_foo()
{
void (*fptr)() = foo;
fptr();
}
You can also use:
void test_foo()
{
void (*fptr)() = foo;
(*fptr)();
}
but the first form is equally valid.
Update, in response to comment by OP
Given the posted definition of the class you would use:
(*Timer1.isrCallback)();
To use
(Timer1.*isrCallback)();
isrCallback has to be defined as a non-member variable of whose type is a pointer to a member variable of TimerOne.
void (TimerOne::*isrCallback)();
Example:
#include <iostream>
class TimerOne
{
public:
void foo()
{
std::cout << "In TimerOne::foo();\n";
}
};
int main()
{
TimerOne Timer1;
void (TimerOne::*isrCallback)() = &TimerOne::foo;
(Timer1.*isrCallback)();
}
Output:
In TimerOne::foo();
(Test this code)
If you want to define isrCallbak as a member variable of TimerOne, you'll need to use:
#include <iostream>
class TimerOne
{
public:
void (TimerOne::*isrCallback)();
void foo()
{
std::cout << "In TimerOne::foo();\n";
}
};
int main()
{
TimerOne Timer1;
Timer1.isrCallback = &TimerOne::foo;
// A little complicated syntax.
(Timer1.*(Timer1.isrCallback))();
}
Output:
In TimerOne::foo();
(Test this code)

How do i write a pointer-to-member-function with std::function?

I know how to declare int fn(double) inside of std::function (std::function<int(double)>). I know how to write a pointer-to-member-function (typedef int (A::*MemFn)(double d);). But how do i write a pointer-to-member-function with std::function?
Dummy code if you feel like compiling/testing
-edit- based on answers i think i'll just use the typedef and not bother with std::function
#include <cstdio>
#include <functional>
struct A{ int fn(double){ return 0; } };
int fn2(double){ return 0; }
typedef int (A::*MemFn)(double d);
typedef std::function<int(double)> MemFn2;
void Test(A*a, MemFn2 fn){
fn(1.2f);
}
void Test(A*a, MemFn fn){
(a->*fn)(1.2f);
}
int main(){
Test(new A, &A::fn);
Test(new A, &fn2);
}
std::function is perfectly capable of storing a member function pointer directly. However, you have to adjust the argument list appropriately. Member pointers must be called with an instance of the type (or a derived type). When putting them in a std::function, the first argument in the argument list is expected to be a pointer (or reference or smart-pointer) to the object type.
So, if I have the following class:
struct Type
{
public:
int Foo();
};
The correct syntax to store this member function in a std::function is:
std::function<int(Type&)> fooCaller = &Type::Foo;
If you want to preserve the argument list (in your case, int(double)), then you need to provide the instance outside of the function. This can be done via std::bind:
struct A{ int fn(double){ return 0; } };
A anInstance;
std::function<int(double)> fnCaller = std::bind(&A::fn, &anInstance, std::placeholders::_1);
Note that it is your responsibility to ensure that the object pointer you provide to std::bind remains alive so long as fnCaller is alive. If you return fnCaller to someone, and it has a pointer to a stack object, you're in trouble.
What's nice is that you could bind a shared_ptr (or any copyable smart pointer) as your object, thanks to how the function call mechanism is defined:
struct A{ int fn(double){ return 0; } };
auto anInstance = std::make_shared<A>();
std::function<int(double)> fnCaller = std::bind(&A::fn, anInstance, std::placeholders::_1);
Now you don't have to worry; the binder will continue to keep the object alive, since it stores a shared_ptr by value.
A member function is not a function. It is not itself anything you can call. All you can do is call a member function of an instance object. Only the pair of pointer-to-member-function and object constitutes a callable entity.
To bind an instance to a PTMF and obtain something callable, use bind:
#include <functional>
struct Foo
{
double bar(bool, char);
};
Foo x;
using namespace std::placeholders;
std::function<double(bool, char)> f = std::bind(&Foo::bar, x, _1, _2);
f(true, 'a'); //...
As with lambdas, bind expressions have an unknowable type, and the conversion to std::function (as well as the actual dispatch) is potentially expensive. If possible, it is preferable to use auto for the type of the bind expression.
One of the guidelines in Scott Meyer's Modern C++11 book is to avoid std::bind and always use a lambda closure instead:
struct A{ int fn(double){ return 0; } };
std::function<int(double)> f = [a = A{}](double x) mutable { return a.fn(x); };
The mutable is necessary here, as the capture a might potentially be changed by the function call (since A::fn is non-const).
You can use std::binder1st to bind member function to a class instance:
typedef std::binder1st<std::mem_fun1_t<int, A, double>> MemFn;
void Test(A* a, double d)
{
MemFn fn(std::mem_fun(&A::fn), a);
int nRetVal = fn(d);
}
int main()
{
Test(new A, 1.2f);
return 0;
}
If you can use Boost then you can use Boost.Bind. It's easily accomplished like this:
boost::bind(&MyClass::MemberFunction, pInstance, _1, _2)
Hopefully it's fairly self-explanatory. _1 and _2 are placeholders for parameters you can pass through to the function.

Non-pointer typedef of member functions not allowed?

After getting an answer to this question I discovered there are two valid ways to typedef a function pointer.
typedef void (Function) ();
typedef void (*PFunction) ();
void foo () {}
Function * p = foo;
PFunction q = foo;
I now prefer Function * p to PFunction q but apparently this doesn't work for pointer-to-member functions. Consider this contrived example.
#include <iostream>
struct Base {
typedef void (Base :: *Callback) ();
//^^^ remove this '*' and put it below (i.e. *cb)
Callback cb;
void go () {
(this->*cb) ();
}
virtual void x () = 0;
Base () {
cb = &Base::x;
}
};
struct D1 : public Base {
void x () {
std :: cout << "D1\n";
}
};
struct D2 : public Base {
void x () {
std :: cout << "D2\n";
}
};
int main () {
D1 d1;
D2 d2;
d1 .go ();
d2 .go ();
}
But if I change it to the new preferred style: typedef void (Base :: Callback) () and Callback * cb, I get a compiler error at the point of typedef
extra qualification 'Base::' on member 'Callback'
Demo for error.
Why is this not allowed? Is it simply an oversight or would it cause problems?
For non-member functions, a type such as typedef void(Function)() has several uses, but for member functions the only application is to declare a variable which holds a function pointer. Hence, other than a stylistic preference, there's no strict need to allow this syntax and it has been omitted from the standard.
Background
The :: is a scope resolution operator, and the syntax X::Y is reserved for static member access if X is a class type. So X::*Z was another syntax invented to define pointer-to-member.
Forget member-function for a while, just think about member-data, and see this code:
struct X
{
int a;
};
int X::*pa = &X::a; //pointer-to-member
X x = {100}; //a = 100
cout << (x.*pa) << endl;
It defines a pointer-to-member-data, and the cout uses it to print the value of a of object x, and it prints:
100
Demo : http://www.ideone.com/De2H1
Now think, if X::pa (as opposed to X::*pa) were allowed to do that, then you've written the above as:
int X::pa = X::a; //not &X::a
Seeing this syntax, how would you tell if X::a is a static member or non-static member? That is one reason why the Standard came up with pointer-to-member syntax, and uniformly applies it to non-static member-data as well as non-static member-function.
In fact, you cannot write X::a, you've to write &X::a. The syntax X::a would result in compilation error (see this).
Now extend this argument of member-data to member-function. Suppose you've a typedef defined as:
typedef void fun();
then what do you think the following code does?
struct X
{
fun a;
};
Well, it defines member a of type fun (which is function taking no argument, and returning void), and is equivalent to this:
struct X
{
void a();
};
Surprised? Read on.
struct X
{
fun a; //equivalent to this: void a();
};
void X::a() //yes, you can do this!
{
cout << "haha" << endl;
}
We can use exactly the same syntax to refer to a which is now a member-function:
X x;
x.a(); //normal function call
void (X::*pa)() = &X::a; //pointer-to-member
(x.*pa)(); //using pointer-to-member
The similarity is the synatax on the right hand side : &X::a. Whether a refers to a member-function or member-data, the syntax is same.
Demo : http://www.ideone.com/Y80Mf
Conclusion:
As we know that we cannot write X::a on the RHS, no matter if a is a member-data or member-function. The only syntax which is allowed is &X::f which makes it necessary that the target type (on LHS) must be pointer as well, which in turn makes the syntax void (X::*pa)() absolutely necessary and fundamental, as it fits in with other syntax in the language.
To be precise the two typedef's in the case of the non-member pointers are not the same:
typedef void function();
typedef void (*fptr)();
The first defines function as a function taking no arguments and returning void, while the second defines ftpr as a pointer to function taking no arguments and returning void. The confusion probably arises as the function type will be implicitly converted to a pointer type in many contexts. But not all:
function f; // declares void f();
struct test {
function f; // declares void test::f()
};
void g( function f ); // declares g( void (*f)() ): function decays to pointer to function in declaration
g( f ); // calls g( &f ): function decays to pointer to function
void f() {} // definition of f
// function h = f; // error: cannot assign functions
function *h = f; // f decays to &f
Let's skip the "function" part for a second. In C++, we have the int, the int* and the int Foo::* types. That's a regular integer, pointer to integer, and a pointer to an integer member. There is no fourth type "integer member".
Exactly the same applies to functions: there's just no type "member function", even though there are function types, function pointer types, and member function pointer types.