[6 函数子类及函数] 42. 确保less<T>与operator<具有相同的语义(POLA)

假设Widget包含一个重量值和一个最大速度值:

class Widget {
public:
    ...
    size_t weight() const;
    size_t maxSpeed() const;
    ...
};

通常情况下,按重量对Widget排序是最自然的方式:

bool operator<(const Widget& lhs, const Widget& rhs)
{
    return lhs.weight() < rhs.weight();
}

假如我们需要创建一个按照最大速度进行排序的multiset<Widget>容器。multiset<Widget>的默认比较函数是less<Widget>,而less<Widget>在默认情况下会调用operator<来完成它的工作。一种方法是特例化less<Widget>,切断less<Widget>和operator<之间的关系,让它只考虑Widget的最大速度:

// 这是std::less对Widget的特化版本;一种不好的做法
template<>
struct std::less<Widget> : public std::binary_function<Widget, Widget, bool> {
    bool operator()(const Widget& lhs, const Widget& rhs) const
    {
        return lhs.maxSpeed() < rhs.maxSpeed();
    }
};

作为一般性规则,对std名字空间的组件进行修改通常是禁止的,会导致未定义的行为。但在某些特定情况下,对std名字空间的修补工作仍然是允许的,特别是,针对用户定义的类型,特化std中的模板。下面的例子就是Boost库的智能指针shared_ptr的部分实现:

namespace std {
    // 针对boost::shared_ptr<T>的std::less特化
    template<typename T>
    struct less<boost::shared_ptr<T>> : public     binary_function<boost::shared_ptr<T>, boost::shared_ptr<T>, bool> {
        bool operator()(const boost::shared_ptr<T>& a, const boost::shared_ptr<T>& b) const 
        {
            // shared_ptr::get返回shared_ptr对象的内置指针
            return less<T*>()(a.get(), b.get());
        }
    };
}

这没有什么不合理,上面的less特化只是确保智能指针的排序行为与它们的内置指针的排序行为一致。

让less不调用operator<而去做别的事情,这会无端地违背程序员的意愿,违背了最小惊讶原则POLA(the principle of least astonishment)。

回到那个按照最大速度对multiset<Widget>容器进行排序的例子,你只需要创建一个函数子类,然后让这个函数子类完成你所期望的比较操作:

struct MaxSpeedCompare: public binary_function<Widget, Widget, bool> {
    bool operator()(const Widget& lhs, const Widget& rhs) const
    {
        return lhs.maxSpeed() < rhs.maxSpeed();
    }
};

我们使用MaxSpeedCompare作为比较类型来创建我们的multiset:

multiset<Widget, MaxSpeedCompare> widgets;

总结:

应该尽量避免修改less的行为,因为这样做很可能会误导其他的程序员,违背POLA程序设计原则。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值