6

我知道以前有人问过这个问题,但尽管我是一个相当有经验的编码员,但我不明白答案,也没有办法回答这些以前的问题以要求澄清。没有“回复”链接或任何东西。此外,这些问题已经很老了。所以,我重新提出这个问题。

我有一个类,我在其中重载了 += 运算符。我希望一个重载采用裸函数指针,另一个重载采用 std::function:

void operator+=(void (*handler)());
void operator+=(function<void (void *, T)> handler);

用法:

MyClass a;
a += [](){ DoSomething(); };
a += [](void *x, T y){ DoSomething(); };

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

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

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

void operator+=(function<void()> handler);

但同样,我不能根据 function<> 模板的签名重载。

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

我多年来一直在使用多种语言进行编程,但我的 C++ 技能有点生疏。

4

2 回答 2

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

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

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

于 2012-12-11T03:15:43.827 回答
0

好的,如果你有一个std::vector<std::function<void()>>你甚至不需要有一堆重载。最简单的方法是定义一个模板化的operator+=,可能的“受保护”,std::enable_if仅对可调用对象或函数指针打开。因此,传递 lambda 或原始指针将在分配时为您自动转换(push_back/emplace_back)。通过std::function将按预期分配。

于 2012-12-11T02:46:02.033 回答