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.
Related
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 (*)()'
}
I'm trying to understand template argument deduction with regular functions, pointer to regular functions, member functions and pointer to member functions. Can someone explain why the last line yields a compile error while there is no issue with standalone?
#include <iostream>
#include <type_traits>
struct A {
int fun(float, char) const&;
};
void standalone(int, char) {}
template <typename T>
void what(T &&) {
std::cout << __PRETTY_FUNCTION__ << "\n";
}
int main()
{
what(standalone); // void what(T&&) [with T = void (&)(int, char)]
what(decltype(&standalone){}); // void what(T&&) [with T = void (*)(int, char)]
what(decltype(&A::fun){}); // void what(T&&) [with T = int (A::*)(float, char) const &]
what(A::fun); // main.cpp: In function 'int main()':
// main.cpp:30:13: error: invalid use of non-static member function 'int A::fun(float, char) const &'
| // what(A::fun);
| ^~~
}
The problem is that we cannot pass a reference to a member because from Pointers to members:
The type “pointer to member” is distinct from the type “pointer”, that is,
a pointer to member is declared only by the pointer to member declarator syntax, and never by the pointer
declarator syntax. There is no “reference-to-member” type in C++.
This means that we must explicitly use the address of operator in the call expression to pass a pointer to member instead(since reference to member is not allowed), as shown below:
//-------v---------> must explicitly use address of operator
what(&A::fun);
Side note
Although irrelevant in your case, note that unlike ordinary function pointers, there is no automatic conversion between a member function and a pointer to that member. That is, in case of member functions and in contexts where a pointer is expected(allowed) the expressions A::fun and &A::fun are not equivalent.
For a standalone function, a pointer to function can be converted contextually to function reference, e.g. in order to be called. A function can be converted to a pointer to itself. In result those two lines are both legal and equal.
what(standalone);
what(*********************************************standalone); // stars!
For every star its argument is a reference and is contextually converted to a pointer, the result would be a reference, and so on. In C++ a function (reference) is a type.
The expression &standalone is explicitly a pointer, so what(&standalone); would be using a pointer.
Now a pointer to member is a type distinct from a usual pointer and has no analog in form of reference. The only legal way to obtain a pointer to member function or member variable is to combine unary operator& with its nested name.
Non-static member functions are very different from free functions. They can only be used in a very limited number of ways.
The only possible uses for a non-static member function are in a member access expression to call the function or as an operand to & to form a pointer-to-member.
A::fun by itself isn't even syntactically correct in an expression if it is not preceded by & or a member access operator. decltype(A::fun) is also ill-formed.
This question is a follow-up of A question regarding the implementation of std::add_pointer
Under std::add_pointer
there is the following reference:
Otherwise (if T is a cv- or ref-qualified function type), provides the
member typedef type which is the type T.
Based on reading Non-static member functions: const-, volatile-, and ref-qualified member functions, my understanding is that a for a non-static member function with given cvand/or ref qualification,
a) the cv qualification of the function applies to the this pointer as well, within the scope of the function
b) the ref qualification of the function does not apply to the this pointer within the scope of the function
Given this, why is it that std::add_pointer cannot provide the member typedef type T* in the case of a non-static member function with cv or ref qualification?
Per [dcl.ptr]/4:
[ Note: Forming a pointer to reference type is ill-formed; see
[dcl.ref]. Forming a function pointer type is ill-formed if the
function type has cv-qualifiers or a ref-qualifier; see
[dcl.fct]. Since the address of a bit-field cannot be taken, a
pointer can never point to a bit-field. — end
note ]
The pointer-to-cv-qualified-function type you are imagining is actually nonexistent. Therefore, std::add_pointer cannot produce such a type :)
A non-static member function type cannot be formed. Such a thing does not exist.
struct T {
int func() const;
};
func does not have a type. You cannot ever use it as an expression on its own.
using mf = int (T::*)() const;
mf myfunc = &T::func;
mf is a pointer to member function type. It is not a function type; pointers to non-static members (including member functions) are data, not functions.
A cv or ref qualification on a member function does not qalify the function type, which does not exist, but the type of the implicit "this" parameter.
The paragraph you quote only applies to non-member or static member functions.
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.
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.