I am wondering why the following code is correct:
void foo(){}
void foo2(void(*)()){};
void foo3(void(*)()&){};
int main(){
foo; // type void(&)() lvalue
foo2(foo); // void(&)() -> void(*)() function to pointer conversion
foo3(foo); // ?? conversion
}
According to the function to pointer
conversion here
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.
The conversion is fine from the void(&)() to the void(*)(), but not void(*)()&.
What is the reason for this code snippet (especially line with ??) to be correct?
The parameter of foo3
which is void(*)()&
is actually a function pointer with a ref-qualifier. This is not allowed by the standard.
The C++17 standard draft n4659 states :
A function type with a cv-qualifier-seq or a ref-qualifier (including a type named by typedef-name) shall appear only as:
(6.1) — the function type for a non-static member function,
(6.2) — the function type to which a pointer to member refers,
(6.3) — the top-level function type of a function typedef declaration or alias-declaration,
(6.4) — the type-id in the default argument of a type-parameter, or
(6.5) — the type-id of a template-argument for a type-parameter.
The parameter of foo3
does not meet any of the criteria above. The closest to what you are trying to do is (6.2).
So you can have this instead:
void foo(){}
class C {
public:
void foo1() & {}
};
void foo2(void(*)()){};
void foo3(void(C::*)()&){};
int main(){
(void) foo;
foo2(foo);
foo3(&C::foo1);
}
This compiles on both GCC and Clang. Demo here.