我知道这个问题之前已被问过,但尽管我是一位经验丰富的编码员,但我不理解答案,也没有办法回答这些先前的问题,要求澄清。没有“回复”链接或任何东西。此外,这些问题还很旧。所以,我重新问这个问题。
我有一个类,我正在重载+ =运算符。我想要一个重载来获取一个裸函数指针,另一个需要一个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);
但同样,我不能根据函数&lt;&gt;的签名重载模板。
有关更多示例,请参阅此主题:Isn't the template argument (the signature) of std::function part of its type? (我尝试实现该线程中提到的各种解决方案,并且没有一个会编译)
我已经用多种语言编程了很多年,但我的C ++技能有点生疏。
答案 0 :(得分: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
类型。
答案 1 :(得分:0)
好的,如果你有一个std::vector<std::function<void()>>
,你甚至不需要一堆重载。最简单的方法是定义一个模板operator+=
,可能“保护”std::enable_if
只能为可调用对象或函数指针打开。所以传递lambdas或原始指针将在assign(push_back / emplace_back)上为你做自动转换。传递std::function
将按预期分配。