Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why function pointer of overloaded function need static_cast?

For the below code, I get the error

#include <iostream>
#include <functional>

using namespace std;

class A {};
class B {};

namespace N
{
    void func(A a, int z){}
    void func(B a, int z){}
}

void func_1(std::function<void(A, int)> x)
{
    A a;
    x(a, 1);
}

int main()
{
    func_1(N::func);
    
    return 0;
}

Error:

    main.cpp:23:19: error: cannot resolve overloaded function 'func' based on conversion to type 'std::function<void(A, int)>'
   23 |     func_1(N::func);

If we do the static cast for the func_1(N::func); as func_1(static_cast<void (&)(A, int)>(N::func));, then this work fine. But I would expect this to work without a cast.

like image 816
Swapnil Avatar asked Oct 20 '20 14:10

Swapnil


People also ask

Why are function pointers needed?

Function pointers can be useful when you want to create callback mechanism, and need to pass address of a function to another function. They can also be useful when you want to store an array of functions, to call dynamically for example.

How do you declare a function pointer in C++?

We declare the function pointer, i.e., void (*ptr)(char*). The statement ptr=printname means that we are assigning the address of printname() function to ptr. Now, we can call the printname() function by using the statement ptr(s).

Are function pointers safe?

Pointers to member functions in C++ This is how C++ uses function pointers when dealing with member functions of classes or structs. These are invoked using an object pointer or a this call. They are type safe in that you can only call members of that class (or derivatives) using a pointer of that type.

What do you mean by overloading of a function?

Function overloading is a feature of object-oriented programming where two or more functions can have the same name but different parameters. When a function name is overloaded with different jobs it is called Function Overloading.


2 Answers

std::function<void(A, int)> is more complicated than void(*)(A, int).

template< class F >
function( F f );

Initializes the target with std::move(f). If f is a null pointer to function or null pointer to member, *this will be empty after the call. This constructor does not participate in overload resolution unless f is Callable for argument types Args... and return type R.

You don't even know what constructors participate in overload resolution until you decide which N::func you mean.

One can conceive of an combined overload resolution and template argument deduction scheme that could "meet in the middle" by trying std::function<void(A, int)>::function<void(*)(A, int)> among (arbitrarily many) other valid instantiations of the constructor.

Problems abound with that.

  1. It has to provably arrive at an answer. In general there are infinite possible instantiations of the templates. You'd also want it to be able to pick int(*)(A, int) if you passed it int g(A, int).
  2. It really should agree with the current scheme where that arrives at an unambiguous answer.
  3. Each of the compiler vendors have to implement it correctly.
like image 78
Caleth Avatar answered Nov 04 '22 12:11

Caleth


As a handy workaround you can provide this kind of func_1 overload.

...

void func_1(void(*x)(A, int))
{
    func_1(std::function<void(A, int)>{x});
}

Now it works as desired without static_cast: demo

like image 42
Marek R Avatar answered Nov 04 '22 13:11

Marek R