如何使用C ++中支持比较器的模板实现容器?

时间:2015-12-12 12:50:44

标签: c++

我想实现一个泛型类型元素的容器;我希望这个容器支持比较器。

当使用STL的优先级队列时,我可以定义一个比较器并初始化我的优先级队列容器实例,如下所示:

bool IsMyItemLarger(MyItem* a, MyItem* b) {
    if(a && b && a->value > b->value)
        return true;
    return false;
}

std::priority_queue<
    MyItem*, 
    vector<MyItem*>, 
    std::function<bool(MyItem*, MyItem*)>
> pq(IsMyItemLarger);

现在,我想定义自己的容器类,我希望它支持包括基本类型在内的任何类型,因此模板T应该在类定义中。

template<typename T...>
class MyContainer {
public:
    vector<T*> items;
};

但是,如何在容器类中定义比较器存根? (以便客户端可以传递例如&#34; bool(MyItem *,MyItem *)&#34;作为模板参数和&#34; IsMyItemLarger&#34;作为构造函数的参数?)

注意:(关于以下主题的内容!!)

我知道如何通过接口实现SIMILAR类,例如

我定义了一个接口,只有符合此接口的项才能插入到容器中。它可以通过编译(以下代码)

class AbstractBaseItem {
public:
    virtual int compareTo(AbstractBaseItem* a) = 0;
};

class MyContainer {
public:
    vector<AbstractBaseItem*>   items;
    bool greater(int i, int j) {
        return items[i]->compareTo(items[j]) > 0;
    }
};

class MyItem : public AbstractBaseItem {
public:
    int value;
    int compareTo(AbstractBaseItem* a) {
        int aValue = ((MyItem*)a)->value;
        if(value > aValue)
            return 1;
        else if(value < aValue)
            return -1;
        else
            return 0;
    }
};

但是,从逻辑上讲,我不想使用虚拟功能。容器中的所有项目应该是完全相同的类型,而不是&#34; as-is&#34;类型。例如。我只是希望MyItem在容器中,而不是MyItem,YourItem,HisItem等,尽管这些类都继承自AbstractBaseItem。它可能是一个原始类型,如int,long,double ......

所以模板实际上就是我想要的。

1 个答案:

答案 0 :(得分:2)

比较被委托给另一个模板类型,为方便起见,通常会默认为std::greater<T>,它完全按照它的样子行事;它已经在标准库中提供,还有许多其他操作,如lessgreater_equal等,因此无需重写它们。它们被称为运算符包装器,可用于 <functional>

因此,

template<typename T, typename Compare>
//                   ^^^^^^^^^^^^^^^^
class MyContainer {

    vector<T*> items;
    /* public: */Compare compare;

    // ...
    { 
       if ( compare(T1, T2) )

    }
};

Compare的签名必须是

template <class T> bool cmp(const T&, const T&);

或类似的,以保持标准设计,其中cmp(a, b)应该是一个有效的表达式;当然,你的可能会有所不同。有关它的更多信息here

容器通常允许您使用他们收到的比较器对象,因此您可能也希望将其设为public

提示,如果我可以:

  • 保持vector<T>:指针不好;如果你必须使用它们,请选择智能指针。
  • 您不需要std::function,只需要一个可调用的对象(普通函数,lambda ecc。)