繁体   English   中英

使用自制的 `std::Compare` 初始化 `std::priority_queue` 时避免使用模板吗?

[英]Avoid template when initializing `std::priority_queue` with home-made `std::Compare`?

是否可以去掉以下代码中的模板?

这个想法是将std::priority_queue与通过自制抽象类尊重Compare概念的类一起使用。 我遇到的一些问题是:

  • 优先级队列不会用抽象的比较来初始化。
  • Compare继承的类没有默认构造函数,因为它们都有特定的参数。
  • Algorithm负责初始化Compare实例使用的数据结构。
  • 编辑:可能存在Algorithm几种实现,使用需要Compare不同数据结构,并且该类的用户应该能够决定他想要使用哪个 Compare 。

我不喜欢此后给出的设计,因为实现Algorithm并没有真正被迫调用Compare::attach并且Compare类因此应该具有状态管理(此处未显示)。

它还强制用户指定一个比较模板并传递相应的实例(因为编译器无法在Algorithm的构造函数中推断它)。 make_algo函数可以缓解这种情况,但我宁愿避免这种奇特的构造(不是那种奇特的,但仍然如此)。

是否有一种设计可以在Algorithm使用Compare抽象类而不是模板?

#include <vector>
#include <queue>

class Compare
{
private:
    std::vector<int>* _costs;
protected:
    std::vector<int>& costs() {return *_costs;}
    int cost(const int i) const {return (*_costs)[i];}
public:
    Compare() : _costs(nullptr) {}
    void attach(std::vector<int> & costs_) {_costs = &costs_;}
    virtual bool operator()( const int a, const int b ) const = 0;
};

struct CompCosts : public Compare
{
    virtual bool operator()( const int a, const int b ) const
    {
        return this->cost(a) < this->cost(b);
    }
};

struct CompEps : public Compare
{
    const int eps;
    CompEps(const int e) : Compare(), eps(e) {}
    virtual bool operator()( const int a, const int b ) const
    {
        return this->cost(a)-eps < this->cost(b)+eps;
    }
};


template<typename C>
struct Algorithm
{
    C & comp;
    Algorithm(C& comp_) : comp(comp_) {}
    virtual void operator()() const = 0;
};

template<typename C>
struct Algo : public Algorithm<C>
{
    Algo(C & comp_) : Algorithm<C>(comp_) {}
    virtual void operator()() const
    {
        std::vector<int> costs;
        this->comp.attach(costs);
        std::priority_queue<int, std::vector<int>, C > queue(this->comp);
    }
};

template<typename C>
Algo<C> make_algo(C& comp)
{
    return Algo<C>(comp);
}


int main()
{
    CompCosts compc;
    Algo<CompCosts> algo0(compc);
    auto algo1 = make_algo(compc);

    CompEps compe(1);
    Algo<CompEps> algo2(compe);
    auto algo3 = make_algo(compe);
}

EDIT2: 由于 Barry 提出的解决方案对大家来说可能并不明显,这里是相应的代码

#include <iostream>
#include <vector>
#include <queue>
#include <functional>
#include <cassert>

struct Compare
{
    virtual bool operator()( const int a, const int b, const std::vector<int>& costs ) const =0;
};

struct CompCosts : public Compare
{
    virtual bool operator()( const int a, const int b, const std::vector<int>& costs ) const
    {
        return costs[a] < costs[b];
    }
};

struct CompEps : public Compare
{
    const int eps;
    CompEps(const int e) : Compare(), eps(e) {}
    virtual bool operator()( const int a, const int b, const std::vector<int>& costs ) const
    {
        return costs[a]-eps < costs[b]+eps;
    }
};


struct Algorithm
{
    std::function<bool(const int, const int, const std::vector<int>& costs )> comp;

    Algorithm(
            std::function<
                bool(const int, const int, const std::vector<int>& costs )
            > comp_
        ) : comp(comp_) {}
    virtual void operator()() const = 0;
};

struct Algo : public Algorithm
{
    Algo(std::function<bool(const int, const int, const std::vector<int>& costs )> comp_) : Algorithm(comp_) {}
    virtual void operator()() const
    {
        std::vector<int> costs{3,2,1};

        using namespace std::placeholders;
        std::function<bool(const int, const int)> f = std::bind(comp, _1, _2, std::cref(costs));

        std::priority_queue<int, std::vector<int>, std::function<bool(const int, const int )> > queue(f);
    }
};


int main()
{
    CompCosts compc;
    Algo algo0(compc);
    algo0();

    CompEps compe(0);
    Algo algo2(compe);
    algo2();
}

由于priority_queue持有Compare类型的对象,任何在那里的多态尝试都会导致切片和失败。 但无论如何,多态性确实是把问题想得太多了(就像我在之前的修订版中所做的那样)。

只需使用类型擦除。 你所有的比较器都会有一个bool operator()(int, int) ,比如:

struct CompCosts
{
    std::vector<int> const& costs;

    bool compare(int lhs, int rhs) const
    {
        return costs[lhs] < costs[rhs];
    }
};

所以它们都可以由std::function<bool(int, int)>

using Q = std::priority_queue<int, std::vector<int>, std::function<bool(int, int)>>;

然后使用您想要使用的任何比较器创建您的Q

Q queue_by_cost(CompCosts{costs});
Q queue_by_eps(CompEps{costs});

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM