Why is there only pointer to function instead of var of function? - c++

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.

Related

Why class can be treated as std::function<float()> but shared_ptr cannot be treated as std::shared_ptr<std::function<float()>>

There was some code that was able to treat a class that implements operator() as an std::function. I then tried to do the same but using shared_ptr:
#include <functional>
#include <memory>
class WhiteNoise {
public:
WhiteNoise() {}
float operator() () {
return 0;
}
};
int main() {
//fails
std::shared_ptr<std::function<float()>> = std::dynamic_pointer_cast<std::function<float()>>(std::make_shared<WhiteNoise>());
//fails
std::shared_ptr<std::function<float()>> = std::make_shared<WhiteNoise>();
//works
std::function<float()> f = WhiteNoise();
}
Why I can treat WhiteNoise as std::function<float()> but not shared_ptr<WhiteNoise> as shared_ptr<std::function<float()>>
Why I can treat WhiteNoise as std::function<float()> but not shared_ptr<WhiteNoise> as shared_ptr<std::function<float()>>
For a similar reason why an int can be assigned to a double, but an int* can't be assigned to a double*. Because there is a defined conversion from int to double, but there is no defined conversion between unrelated pointer types.
Likewise, there is a defined conversion for a callable function object to a std::function. The std::function will make a copy of the object, and call its implemented operator() when needed.
But there is no defined conversion from a std::shared_ptr<T> (ie T*) to a std::shared_ptr<std::function> (ie std::function*) when T is not itself a std::function.
If you have a std::shared_ptr<WhiteNoise> and you want to make a std::shared_ptr<std::function<float()>> out of it (why?), you could do something like this instead:
auto wn = std::make_shared<WhiteNoise>();
auto func = std::make_shared<std::function<float()>>(*wn);
float f = (*func)();

What's the function signature of a member function?

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.

How does this example in standard section 6.8 works?

In standard Section ยง6.8 of the Standard (N3690 draft) I see this weird piece of code :
struct T2 { T2(int){ } };
int a, (*(*b)(T2))(int), c, d;
What is int(*(*b)(T2))(int) ?!
Is b a pointer to T2's constructor ?! or maybe a pointer to function pointer ?
It's weird that the bellow code also compile fine !:
struct T2 { T2(int){ } };
int((*b)(T2));
int (*(*b)(T2))(int)
It declares b as pointer to a function which:
takes T2 as argument
and returns pointer to a function which
takes an int as argument
and returns an int.
One should simplify this declaration using typedefs as:
typedef int (*return_type) (int);
typedef return_type(*function_type) (T2);
Or better use C++11 style type aliases:
using return_type = int(*)(int);
using function_type = return_type(*)(T2);
Then the declaration becomes this:
function_type b; //so simple!
Hope that helps.
It is declaration of variable b. b is a pointer to function with one parameter of type T2. The return type of this function is pointer to function with one parameter int returning int.
This should help you understand what is going on here:
struct T2 { T2(int){ } };
typedef int (*func)(int);
int
(*foo(T2))(int) {
}
func
bar(T2) {
}
int main() {
int (*(*b)(T2))(int);
b = &foo;
b = &bar;
return 0;
}
So this is a function that take a T2 and return a function pointer to a function that return an int and take an int as parameter.
I a add this to my example of why c(++) is an horrible language.
By the way, you cannot take the address of a constructor (C++98 Standard 12.1/12 Constructors - "12.1-12 Constructors - "The address of a constructor shall not be taken.")

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.