为什么复盖操作者()?
-
11-07-2019 - |
题
在 提高信号 库,它们载()操作人员。
这是一个《公约》在C++?回调,等等?
我已经看到这种代码中的一个共同的工人(他是一个很大的推动风扇)。所有提高善,这只有导致混乱,对我来说。
任何见解的原因,这种超负荷?
解决方案
其中一个主要的目标重载operator当()是创建一个仿函数。函子行为就像一个功能,但它有,它是有状态的优点,这意味着它可以保持数据反映了其呼叫之间的状态。
下面是一个简单的算符的示例:
struct Accumulator
{
int counter = 0;
int operator()(int i) { return counter += i; }
}
...
Accumulator acc;
cout << acc(10) << endl; //prints "10"
cout << acc(20) << endl; //prints "30"
函子被重使用通用编程中使用。许多STL算法都写在一个非常普遍的方式,让你可以插入自己的函数/仿到算法。例如,该算法的std ::的for_each允许你的范围内的每个元素上应用的操作。它可以实现类似的东西:
template <typename InputIterator, typename Functor>
void for_each(InputIterator first, InputIterator last, Functor f)
{
while (first != last) f(*first++);
}
您看到,因为它是由一个函数参数化这个算法是非常通用的。通过使用操作符(),这个功能可以让您使用仿函数或函数指针。下面是示出这两种可能性的示例:
void print(int i) { std::cout << i << std::endl; }
...
std::vector<int> vec;
// Fill vec
// Using a functor
Accumulator acc;
std::for_each(vec.begin(), vec.end(), acc);
// acc.counter contains the sum of all elements of the vector
// Using a function pointer
std::for_each(vec.begin(), vec.end(), print); // prints all elements
关于你对运营商的问题()超载,以及是有可能。可以完美写具有几个括号运算函子,只要你尊重方法重载的基本规则(例如仅在返回类型超载是不可能的)。
其他提示
它允许一个类等的功能作用。我有一个日志类用它在呼叫应该是一个功能,但我想这个类的额外的好处。
所以是这样的:
logger.log("Log this message");
变成这样:
logger("Log this message");
许多人回答说,它使一个函子,瞒着一个很大的原因,一个仿函数比普通的旧功能较好。
答案是一个算符可以具有的状态。考虑求和函数 - 它需要保持一个运行总计
class Sum
{
public:
Sum() : m_total(0)
{
}
void operator()(int value)
{
m_total += value;
}
int m_total;
};
一个算符不是一个函数,所以不能过载它。结果 你的同事是正确的,虽然是运营商的重载()用于创建“函子” - 可以这样调用函数的对象。在使用模板期待“功能状”参数组合这可能是非常强大,因为对象和功能之间的区别变得模糊。
作为其他的海报说:函子有优势在于普通函数它们可以具有的状态。这种状态可以在单次迭代中使用(例如,以计算在一个容器中的所有元素的总和)或通过多次迭代(例如找到多个容器满足特定标准的所有元件)。
开始在你的代码更经常使用std::for_each
,std::find_if
等,你就会明白为什么它的方便有重载()运算符的能力。它还允许仿函数和任务,有不会的在派生类的其他方法的名称冲突的明确的调用方法。
您还可以看看在 C ++常见问题的矩阵例如的。有做它很好的用途,但它当然取决于你所要完成的。
函子基本上像函数指针。它们一般被用来可拷贝(如函数指针),并以同样的方式作为函数指针调用。主要的好处是,当你有一个模板仿作品的算法,函数调用operator()可以内联。然而,函数指针仍然有效仿函数。
一张强度我可以看到,然而,这可以被讨论的,是操作者()的签名的外观和行为在不同类型的相同。如果我们有一个类记者其中有一个成员方法报告(..),然后另一个类作家,其中有一个成员方法写(..),我们将不得不写适配器,如果我们想用这两个类为可能其他一些系统的模板组件。所有这将关心的是通过对字符串或者你有什么。如果不使用操作符()重载或写特殊类型的适配器,你不能做的东西像
T t;
t.write("Hello world");
,因为T具有一个要求,即有它接受任何隐式浇注料为const char *(或者更确切地说,为const char [])的成员函数调用写入。本例中的记者类没有这一点,所以具有T(模板参数)是记者将编译失败。
不过,据我可以看到,这将具有不同类型的工作
T t;
t("Hello world");
不过,它仍然明确要求类型T有这样的运营商定义的,所以我们还是有一个要求对T.就个人而言,我不认为它与过多函子奇怪的,因为它们通常使用,但我宁愿看到其他机制的这种行为。在如C#语言中,你可以只通过一个委托。我不是太熟悉C的成员函数指针,但我能想象你能做到有相同的行为以及。
除了语法糖行为,我真的没有看到运营商的优势重载执行这样的任务。
我相信有更多明知谁拥有更好的理由比我的人,但我想我会奠定了我的意见对你的其他人分享。
另一个同事指出,它可能是伪装函子对象作为功能的一种方式。例如,这样的:
my_functor();
真的是:
my_functor.operator()();
那么这意味这样的:
my_functor(int n, float f){ ... };
可用于重载这个问题,以及
my_functor.operator()(int n, float f){ ... };
其他职位已经做得很好描述符()是如何工作的,以及为什么它可能是有用的。
我最近一直在使用一些代码,使非常广泛的使用运营商的()。重载这个操作符的一个缺点是有些IDE变得不那么有效的工具,作为一个结果。在Visual Studio中,通常可以在方法调用右键单击转到方法定义和/或声明。不幸的是,VS是不是足够聪明的指数运营商()调用。特别是在所有的地方重载运算符()定义复杂的代码,它可以是很难弄清楚什么一段代码执行的地方。在一些情况下,我发现我已经运行的代码,并通过它跟踪找到什么实际运行。