Passing static method as argument, no address-of operator required? - c++

class ThreadWorker
{
public:
ThreadWorker(void);
virtual ~ThreadWorker(void);
static void DoSomething();
};
int main()
{
boost::thread thread1(ThreadWorker::DoSomething);
boost::thread thread2(ThreadWorker::DoSomething);
boost::thread thread3(&ThreadWorker::DoSomething);
}
I'm playing around with Boost.Thread and I notice it doesn't seem to matter whether I use the address of operator (&) or not when passing a static member function as an argument. Does it not matter? And if not, why? Is one way more correct than the other?

It effectively does not matter. Functions (free functions and static member functions, not non-static member functions) decay to function pointers. No way is more correct than the other, I happen to prefer the explicit one though.
C++11 Standard, 4.3/1:
An lvalue of function type T can be converted to a prvalue of type “pointer to T.” The result is a pointer to the function.
C++11 Standard, 5.2.2/1 - Function call:
There are two kinds of function call: ordinary function call and member function call. A static member function is an ordinary function.

Related

Does an implicit conversion from function pointer to function exist?

I am primarily making this post to clarify some confusing/misleading information about function pointers that I stumbled upon on Stackoverflow.
Let's begin with an example:
#include <iostream>
void func ()
{
std::cout<<"func here"<<'\n';
}
int main()
{
void (*fp)()=func;
void (&fref)()=func;
func();//call through function
(&func)();//call through function pointer
(*fp)();//call through function
fp();//call through function pointer
fref();//call through function
(&fref)();//call through function pointer
}
This prints:
func here
func here
func here
func here
func here
func here
As can be seen a function can be used in place of a function pointer most of the time thanks to function to function pointer decay 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.
But apart from that it looks a function pointer can also be used in place of a function as I can use it to call a function without explicitly derefencing.
Furthermore this Stackoverflow answer
Note also that you do not need to use the unary * to make the call via the function pointer; both (*p1_foo)(); and (p1_foo)(); have the same result, again because of the function-to-function-pointer conversion.
and this Stackoverflow answer
There's a dual convenience as well: a function pointer in call position is automatically converted to a function value, so you don't have to write * to call through a function pointer.
Make it seem like there exists an implicit function pointer to function conversion.
No
An implicit conversion from function pointer to function doesn't exist.
As of ISO International Standard ISO/IEC 14882:2020(E) – Programming Language C++ there are no mentions of such a conversion.
But apart from that it looks a function pointer can also be used in place of a function as I can use it to call a function without explicitly derefencing.
This is probably why some SO answers (and even some less known C++ books!) come to the incorrect conclusion that a function pointer is essentially the same as a function and use the function to function pointer decay as evidence. However this implicit conversion only works in one way! Meaning that the quoted section of the first SO answer is incorrect.
Why does the function call succeed anyway?
The reason as to why we can call a function using a function pointer without explicit derefernce actually lies in the way the built in function call operator "()" works cppreference:
The expression that names the function can be
a) lvalue expression that refers to a function
b) pointer to function
c) explicit class member access expression that selects a member function
d) implicit class member access expression, e.g. member function name used within another member function.
Aha! So the function call operator can directly take a function pointer as expression. There is no implicit conversion. If you read the quote from the second SO answer it explicitly mentions that the function pointer needs to be in call position that is called using the function call operator.
This also means that in all contexts outside of a function call a function pointer does need to be dereferenced where a function is expected such as when initializing a function reference:
void func ()
{
std::cout<<"func here"<<'\n';
}
int main()
{
void (*fp)()=func;//OK (implicit function to function pointer decay)
void (&&fref1)()=&func;//error: invalid initialization of reference of type 'void (&&)()' from expression of type 'void (*)()'
void (&fref2)()=*fp;//OK
void (&fref3)()=fp;// error: invalid initialization of reference of type 'void (&)()' from expression of type 'void (*)()'
}

C++ syntax: & in front of class name in Pybind11 [duplicate]

We know that to create a "common" pointer to a function we can do for example:
void fun();
void (*ptr)() = fun;
The name of a function is also the address where the function start. So I do not need to use the address operator & like this:
void (*ptr)() = &fun;
Now for a pointer to a member function on the contrary I must use the address operator. For example for a class A with a pointer to member function ptr and a function fun() I must write:
void(A::*ptr)() = &A::fun;
Why this difference?
According to the C++ standard:
4.3 Function-to-pointer conversion [conv.func]
An lvalue of function type T can be converted to a prvalue of type
“pointer to T”. The result is a pointer to the function.
This conversion never applies to non-static member functions because
an lvalue that refers to a non-static member function cannot be
obtained.
I think difference is because A::fun is non-static member of class A. I mean, if your fun() is static member of A it will be like for ordinary function. Try it.
It is because now that function is defined inside the class. Pointer to member function holds the "relative address" of where the function is in the class layout and so you have to access it that way.
In case of static, it has no this pointer and it behaves like a global function and so, you can access it like normal function pointer.

Implicit object parameter C++

In this link : Implicit object parameter
In this quote :
If any candidate function is a member function (static or non-static) that does not have an explicit object parameter (since C++23), but not a constructor, it is treated as if it has an extra parameter (implicit object parameter) which represents the object for which they are called and appears before the first of the actual parameters.
I do not understand why the word static is mentioned here? Isn't the implicit object parameter the this pointer ( which only exists in non-static functions ) ?
Edit
in this link : link
quote :
The keyword this is a rvalue (until C++11)prvalue (since C++11) expression whose value is the address of the implicit object parameter (object on which the non-static member function is being called). It can appear in the following contexts:
It's useful to consider examples. When you have:
struct C {
void f(int);
void f(int) const;
};
C c;
c.f(42);
How does overload resolution pick? You effectively have a choice of:
// implicit object | regular
// parameter | parameter
void f(C&, int );
void f(C const&, int );
With the arguments (C, int). That ends up picking the first one, for being a better match.
Now, let's think of this example:
struct D {
static void g(int);
void g(long);
};
D d;
d.g(42);
Now, if we try to do the same thing:
// implicit object | regular
// parameter | parameter
void g(????????, int );
void g(D&, long );
We have two arguments, a D and an int. We don't know if we're going to call a static function or not yet, we still have to do overload resolution. How do we pick in this case? The non-static member function has an implicit object parameter, D&, but what do we do for the static one?
The C++ answer is we contrive a fake parameter, that is a perfect match for everything:
// implicit object | regular
// parameter | parameter
void g(contrived-match, int );
void g(D&, long );
And now, when we do overload resolution with (D, int), you can see that the static function is the best match (better conversion sequence for the second parameter).
Once we pick the static member function, we then ignore the object argument entirely. d.f(42) basically evaluates as D::f(42). But we didn't know that until we performed overload resolution - the contrived parameter exists to solve the problem of how to actually compare these cases.
This still applies even if there were just the one static member function - since d.f(42) does have two parameters: the d and the 42, so the language needs to handle the d somehow (the alternative could've been to simply disallow this syntax, requiring D::f(42) if you wanted to call a static member function, but that seems a lot less nice).
Consider what happens if you don't have this rule and have a static method and non-static method with the same (explicit) parameters. Then to the non-static method an additional implicit parameter (this) will be added, but not to the static method. This will make the list of parameters of both methods different and will allow to overload the static method with non-static method with the same explicit parameters.
First things first, there is a difference between implicit object parameter and this pointer. The former is a reference type while the latter is a keyword and is an rvalue of pointer type. For example for a const qualified non-static member function the implicit object parameter is of type const X& while the this pointer is of type const X*. While for a non-const nonstatic member function the implicit object parameter is of type X& and the this is of type X*. This can be confirmed here.
isn't Implicit object parameter the ( this ) pointer ( which ( the ( this ) pointer ) only works with non-static functions )
No, both static as well as non static member functions have an implicit object parameter for the purposes of overload resolution as can be seen from over.match.funcs#2 which states:
The set of candidate functions can contain both member and non-member functions to be resolved against the same argument list. So that argument and parameter lists are comparable within this heterogeneous set, a member function is considered to have an extra parameter, called the implicit object parameter, which represents the object for which the member function has been called. For the purposes of overload resolution, both static and non-static member functions have an implicit object parameter, but constructors do not.
(emphasis mine)

Copying c++ lambda to Function Pointer reference

I am not sure if I have defined behaviour in the following situation:
My Function pointer type:
typedef void (*DoAfter_cb_type)(void);
The Function which should assign callbacks:
void DoSomething(DoAfter_cb_type & DoAfter_cb)
{
//...
DoAfter_cb = [](){
//...
};
}
Caller:
DoAfter_cb_type DoAfter_cb = nullptr;
DoSomething(DoAfter_cb);
// Here is something that has to be done after DoSomething but before DoAfter_cb.
if( DoAfter_cb != nullptr){
DoAfter_cb();
}
As I learned here lambdas can be implicitly converted to function pointers.
However thoose are still pointers and I fear that something important for calling the lambda is stored on stack and would be out of scope if I just return the function pointer
I have to use function pointers because i do not have access to std::function in my environment.
With std::function I would expect the lambda object to be stored in the reference variable and I would not have any problems.
Is the behaviour the same as If I would just define an ordinary function or do I have any side effects here?
Is the behaviour the same as If I would just define an ordinary function or do I have any side effects here?
Yes, it's the same. A captureless lambda is convertible to a regular function pointer because, to quote the C++ standard ([expr.prim.lambda.closure]/6, emphasis mine):
The closure type for a non-generic lambda-expression with no
lambda-capture has a conversion function to pointer to function with
C++ language linkage having the same parameter and return types as the
closure type's function call operator. The conversion is to “pointer
to noexcept function” if the function call operator has a non-throwing
exception specification. The value returned by this conversion
function is the address of a function F that, when invoked, has the
same effect as invoking the closure type's function call operator.
So while the lambda goes out of scope, that pointer is backed by a proper function, just as if you had written it yourself at file scope. Functions "live" throughout the entire execution of the program, so the pointer will be valid, always.

Address operator with pointer to member function

We know that to create a "common" pointer to a function we can do for example:
void fun();
void (*ptr)() = fun;
The name of a function is also the address where the function start. So I do not need to use the address operator & like this:
void (*ptr)() = &fun;
Now for a pointer to a member function on the contrary I must use the address operator. For example for a class A with a pointer to member function ptr and a function fun() I must write:
void(A::*ptr)() = &A::fun;
Why this difference?
According to the C++ standard:
4.3 Function-to-pointer conversion [conv.func]
An lvalue of function type T can be converted to a prvalue of type
“pointer to T”. The result is a pointer to the function.
This conversion never applies to non-static member functions because
an lvalue that refers to a non-static member function cannot be
obtained.
I think difference is because A::fun is non-static member of class A. I mean, if your fun() is static member of A it will be like for ordinary function. Try it.
It is because now that function is defined inside the class. Pointer to member function holds the "relative address" of where the function is in the class layout and so you have to access it that way.
In case of static, it has no this pointer and it behaves like a global function and so, you can access it like normal function pointer.