为什么重载函数的函数指针需要static_cast?

问题描述

对于以下代码,我得到了错误

#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;
}

错误

    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);

如果我们将func_1(N::func);的静态类型转换为func_1(static_cast<void (&)(A,int)>(N::func));,则可以正常工作。但我希望它在没有强制转换的情况下也能正常工作。

解决方法

std::function<void(A,int)>void(*)(A,int)更复杂。

template< class F >
function( F f );

使用std::move(f)初始化目标。如果f是函数的空指针或成员的空指针,则*this将在调用后为空。除非参数类型为f的{​​{1}}是 Callable 并且返回类型为Args...的,否则该构造函数不参与重载解析。

您甚至都不知道是什么构造函数参与重载解析,直到您确定要表示的R

可以构想一种组合的重载解析和模板参数推导方案,该方案可以通过在构造函数的其他(任意多个)有效实例中尝试N::func来“满足”。

问题很多。

  1. 必须证明是一个答案。通常,模板有无限可能的实例化。如果您通过std::function<void(A,int)>::function<void(*)(A,int)>,您还希望它能够选择int(*)(A,int)
  2. 它确实应该与当前的方案相吻合。
  3. 每个编译器供应商都必须正确实现它。
,

作为方便的解决方法,您可以提供这种func_1重载。

...

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

现在,它在没有static_cast的情况下可以正常工作:demo