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);
| ^~~
}
CodePudding user response:
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.
CodePudding user response:
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.
CodePudding user response:
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.