【问题标题】:Why is this program overloading () operator?为什么这个程序要重载 () 运算符?
【发布时间】:2010-10-08 08:28:20
【问题描述】:

目前我正在学习标准模板库 (STL)。

在这个程序中,我将一些长值存储在关联容器中,然后根据单元的位置对它们进行排序(根据单元位置的数字)。

代码:

#include <iostream>
#include <set>
#include <functional>

using namespace std;

class UnitLess
{
public:
    bool operator()(long first, long second)
    {
        long fu = first % 10;
        long su = second % 10;

        return fu < su;
    }
};

typedef set<long, UnitLess> Ctnr;

int main(void)
{
    Ctnr store;

    store.insert(3124);
    store.insert(5236);
    store.insert(2347);
    store.insert(6415);
    store.insert(4548);
    store.insert(6415);

    for(Ctnr::iterator i = store.begin(); i != store.end(); ++i)
    {
        cout << *i << endl;
    }
}

但我不明白为什么我们的教授重载了 () 运算符?

谢谢。

【问题讨论】:

  • 在该示例中似乎根本没有调用重载的() 运算符。也许它会在以后的练习中介绍?
  • 是的,当std::set 尝试按排序顺序插入元素时调用它(二进制谓词)
  • @Greg Hewgill operator () 在执行 store.insert(some long value) 时被内部调用;
  • 哦,现在我明白了。我很抱歉造成混乱。
  • @Greg Hewgill 你不需要道歉。毕竟你试图帮助我:)

标签: c++ stl set


【解决方案1】:

该类的目的是实现一个以给定方式对集合中的元素进行排序的函数。这称为谓词。

它被实现为一个仿函数,即通过允许在一个对象上使用函数运算符(这就是 std::set 在幕后所做的)。这样做是 STL 和类似代码调用自定义对象的常用方式。 (函数指针比函数对象(又名函子)更受限制

所以它是这样使用的:

Unitless functor;

functor(123, 124); // returns true or false

std::set 是一个已排序的二叉树,因此它在每次插入时多次调用 Unitless 的 () 运算符来确定每个 long 值的位置。

尝试编译并将一些 printf/std::cout 放在那里,看看会发生什么。

另外,请注意,这样的回调(即当您看不到对代码的调用时)在您的学习曲线开始时会令人恐惧和困惑。

  • 然后你会习惯它并使用它们,因为它们很整洁。
  • 然后您的代码再次变得令人恐惧和混乱,您像躲避瘟疫一样避免它们。
  • 然后,您将成为一名胶带程序员,只在适当的地方使用它们,而不是在其他地方使用它们。

;)

【讨论】:

    【解决方案2】:

    UnitLessbinary predicate,它必须是 STL 中带有两个参数的可调用对象。

    通过重载UnitLess 中的函数调用运算符,该类型的实例可以像使用两个longs 并返回一个bool 的函数一样使用。

    UnitLess f;
    f(5, 10);
    

    等价于

    bool f(long first, long second)
    {
        long fu = first % 10;
        long su = second % 10;
    
        return fu < su;
    }
    f(5, 10);
    

    【讨论】:

    • 对不起,初学者,我听不懂你想说什么:(
    • @Space_C0wb0y operator () 在执行 store.insert(some long value) 时被内部调用;
    • 为什么需要提供谓词对象? IIRC,std::set&lt;T, Pred&gt; 将使用默认构造的谓词(即Pred())。在这里,UnitLess 是默认可构造的。此外,如果您不提供谓词 objectstd::set&lt;T, Pred&gt; 会做什么?显然不能使用std::less&lt;T&gt;()
    • @MSalters:我也在考虑这个问题,实际上正要测试它,因为我找不到说明该对象将是默认构造的文档。
    • @MSalters 如果我没有通过 Unitless,那么它会按升序对它们进行排序。但我想根据他们所在单位的位置对它们进行排序。例如 150 和 145。在此示例中,0 小于 5,因此我将按自定义 oder 150 然后 145 进行排序。
    【解决方案3】:

    他实现了一个用于 std::set 的自定义比较,它只比较单位,即模 10 的数量。因为 std::set 是一个模板,它只是尝试调用看起来像函数的东西,无论是否它是不是一个。通过重载 operator() 你可以让它像一个函数一样工作。

    在某些情况下这样做实际上会非常强大,因为结构/类可以存储状态以及额外的参数。整个 boost::function / boost::bind 都是基于这样做的(你不需要每次都创建一个类)。

    在实际编码的示例中可能存在一个小缺陷,因为该练习只是按单位对它们进行排序,但它可以很好地消除具有相同单位但实际上不重复的数字。在您的示例代码中没有这样的示例(您有一个副本,但这是整个值的副本)。如果除了 4548 之外还有 3478,则 Set 比较器会认为它们相同,并且不允许重复。

    顺便说一句,我不确定 set 是我所说的“关联”容器,它指的是键值对。集合中没有关联的值,只有键。

    还有一点:operator() 应该是 const。

    【讨论】:

    • 你确定不是Associative Container吗? sgi.com/tech/stl/set.html 说是Sorted Associative Container
    • sgi.com 的文档作者认为它是一个关联容器,但这似乎与 wikipedia 上的描述不匹配,即en.wikipedia.org/wiki/Associative_array,其中似乎应该有一些与密钥关联的值。你可以说一个键将一个值映射到它自己。当然,std::set 的实现者和任何其他语言的等价物可能很希望使用与 map 相同的实现,即树。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-27
    • 1970-01-01
    相关资源
    最近更新 更多