Search code examples
c++type-conversionimplicit-conversion

function to pointer reference conversion


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?


Solution

  • 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 :

    [dcl.fct]/6

    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.