【问题标题】:Compile-time "opposite" of std::less?std::less 的编译时“相反”?
【发布时间】:2018-11-14 16:03:57
【问题描述】:

提前道歉。我很难为这个问题找到正确的措辞......

作为练习,我正在研究一个固定大小的优先级队列,该队列丢弃大于最大值的对象(用于查找 X 最小对象的队列)并丢弃小于最小值的对象(用于持有最大 X 的队列对象)。问题是是否有办法在编译时达到比较器的逻辑“对立面”。

请参阅下面代码中的注释行:

template <
    typename T, 
    typename Container = std::vector<T>, 
    typename Compare = std::less<typename Container::value_type>>
class fixed_size_priority_queue : public std::priority_queue<T, Container, Compare>
{
    typename Container::size_type maxSize;
    using base = std::priority_queue<T, Container, Compare>;

  public:
    fixed_size_priority_queue(std::size_t size) : base(), maxSize(size)
    {
        base::c.reserve(size);
    }
    void push(T value)
    {
        if (base::size() < maxSize)
        {
            base::push(value);
        }
        // is there some way of arriving at compile-time opposite of 'comp'?
        else if (!base::comp(base::top(), value))
        {
            while (base::size() >= maxSize)
            {
                base::pop();
            }
            base::push(value);
        }
    }
};

void test_fixedPriQueue()
{

    using smallestInts = fixed_size_priority_queue<int>;
    smallestInts fq(4);
    fq.push(5);
    fq.push(3);
    fq.push(5);
    fq.push(5);
    fq.push(7);
    fq.push(11);
    fq.push(1);
    fq.push(2);
}

int main(int argc, char const *argv[])
{
    test_fixedPriQueue();
    return 0;
}

我只是简单地使用了 not (!) 操作符来完成这项工作,但这是否会导致运行时成本(尽管非常小)?当我的班级使用Compare = std::less时,有没有办法到达std::greater_equal

我希望使用std::not&lt;Compare&gt; 之类的东西,当Compare 模板参数为std::less 时,它会解析为std::greater_equal。这有意义吗?

** 编辑 **

尝试 sergeyA 的建议得到了我想要的结果:

template<typename T, typename Comparison>
struct logical_opposite
{
    using op = void;
};

template <typename T>
struct logical_opposite<T, std::less<T>>
{
    using op = std::greater_equal<T>;
};

template <typename T>
struct logical_opposite<T, std::greater<T>>
{
    using op = std::less_equal<T>;
};

然后在priority_queue派生的类中,实例化逻辑相反的函数对象,推入队列时使用:

//...
typename logical_opposite<T, Compare>::op not_comp;

public:
fixed_size_priority_queue(std::size_t size) : base(), maxSize(size), not_comp()
//....

比较函子类型之间存在逻辑关系,我希望这种关系在 STL 中表达出来。

【问题讨论】:

  • 即使会有一些微不足道的开销(优化可能没有),我看不出如果没有!,你如何从less 获得greater_equal。老实说,这似乎是教科书式的过早优化。
  • @YSC 我确实看到了这个,但注意到它已被弃用并且很快就会过时。
  • 有一个很好的理由:自从 lambdas 以来它已经过时了。
  • 您可以创建一个模板化特征,它将根据模板参数选择相反的版本,并指定每次转换。乏味,并且可能没有可量化的性能优势。

标签: c++ templates template-meta-programming


【解决方案1】:

!&lt;&gt;= 在原始类型上没有明显区别,因此您对运行时成本的担忧是没有根据的。

C++ 不是汇编。它描述了抽象机器的行为。编译器将其映射到汇编中,没有明显差异的操作可以在汇编中以相同的方式实现。

虽然在 C++ 中学习什么是“可观察的”需要一些经验,但一般规则是编写干净的代码,在合理的情况下避免分配,保持 da 连续并保持 O-notation 速度正常,然后在你之前测试程序的性能问题担心其他问题。

!&lt;&gt;= 不是“避免过早悲观”问题之一,因此除非在分析时找到代码,否则应忽略它。

【讨论】:

  • 也许提到运行时成本已经脱离了我真正要问的意思。问题是是否有一种内置方法可以推断出not (std::less) 在编译时更简单地表示为std::greater_equal
  • “没有明显差异的操作可以在汇编中以相同的方式实现”。理论上是可以的,但是很多时候编译器不这样做。但你说得对,额外的否定通常不会花费任何成本,因为它可以融合到其他一些操作中。
  • @veefu 比较器传入了,所以肯定不是?
  • @Yakk-AdamNevraumont 我在问题中添加了一些内容,这可能在某种程度上澄清了这个问题。您提到“primative 类型的可观察到的差异”。为什么是合格的答案?在这种情况下,更复杂的用户定义类型会发生什么?
猜你喜欢
  • 2021-04-29
  • 2020-10-10
  • 1970-01-01
  • 2012-11-11
  • 1970-01-01
  • 1970-01-01
  • 2012-07-16
  • 1970-01-01
相关资源
最近更新 更多