如何在C++中重载std :: function签名

Sod*_*hty 6 c++ lambda overloading signature

我知道这个问题之前已被问过,但尽管我是一位经验丰富的编码员,但我不理解答案,也没有办法回答这些先前的问题,要求澄清.没有"回复"链接或任何东西.此外,这些问题还很旧.所以,我重新问这个问题.

我有一个类,我正在重载+ =运算符.我想要一个重载来获取一个裸函数指针,另一个需要一个std :: function:

void operator+=(void (*handler)());
void operator+=(function<void (void *, T)> handler);
Run Code Online (Sandbox Code Playgroud)

用法:

MyClass a;
a += [](){ DoSomething(); };
a += [](void *x, T y){ DoSomething(); };
Run Code Online (Sandbox Code Playgroud)

遗憾的是,代码无法编译,因为编译器无法确定第二个重载是否不适合第一个+ =调用.

如何定义我的operator + =成员函数来纠正这个问题?我不想改变运算符的使用方式(例如通过使用显式转换).我希望他们像上面所说的那样工作.

此外,还有以下过载也很方便:

void operator+=(function<void()> handler);
Run Code Online (Sandbox Code Playgroud)

但同样,我不能基于函数<>模板的签名重载.

有关更多示例,请参阅此主题:std :: function的模板参数(签名)是否是其类型的一部分? (我尝试实现该线程中提到的各种解决方案,但没有一个会编译)

我已经用多种语言编程了很多年,但我的C++技能有点生疏.

hps*_*use 3

以下代码适用于 g++ 4.7.2:

#include <functional>
#include <iostream>

template <typename T>
typename std::enable_if<std::is_convertible<T, void(*)()>::value>::type
foo(T&&)
{
    std::cout << "foo(void(*)())" << std::endl;
}

void foo(std::function<void(void*,int)>)
{
    std::cout << "foo(std::function<void(void*,int)>)" << std::endl;
}

int main()
{
    foo([]{});
    foo([](void*,int){});
}
Run Code Online (Sandbox Code Playgroud)

该问题是由 的构造函数引起的std::function,该构造函数声明为template <class F> function(F);。该构造函数接受所有内容作为其参数。如果该参数没有适当的operator(),则在构造函数的实例化过程中会生成错误。

不幸的是,重载解析过程不需要实例化任何模板函数,因此编译器认为所有内容都可以转换为任何std::function类型。