【问题标题】:Using std::less<> for unique_ptr to raw pointer comparison fails to compile, but works with wrapper?将 std::less<> 用于 unique_ptr 与原始指针的比较无法编译,但可以与包装器一起使用?
【发布时间】:2020-10-30 16:45:49
【问题描述】:

我想通过原始指针在一组std::unique_ptr 中进行搜索,而不是编写自己的比较器类,我决定使用std::less&lt;&gt; 的透明属性。

这是基于cppreference example 的示例代码。

这不能编译:

#include <memory>
#include <set>

using FatKey = std::unique_ptr<int>;
using LightKey = int;

bool operator<(const FatKey& fk, LightKey* lk) { return fk.get() < lk; }
bool operator<(LightKey* lk, const FatKey& fk) { return lk < fk.get(); }
bool operator<(const FatKey& fk1, const FatKey& fk2) { return fk1.get() < fk2.get(); }

int main()
{  
    std::set<FatKey, std::less<>> example2;
 
    LightKey lk = 2;
    auto search2 = example2.find(&lk);
}

虽然这很好用:

#include <memory>
#include <set>

template<typename T>
struct UPtrWrapper { std::unique_ptr<T> ptr; };

using FatKey = UPtrWrapper<int>;
using LightKey = int;

bool operator<(const FatKey& fk, LightKey* lk) { return fk.ptr.get() < lk; }
bool operator<(LightKey* lk, const FatKey& fk) { return lk < fk.ptr.get(); }
bool operator<(const FatKey& fk1, const FatKey& fk2) { return fk1.ptr.get() < fk2.ptr.get(); }

int main()
{  
    std::set<FatKey, std::less<>> example2;
 
    LightKey lk = 2;
    auto search2 = example2.find(&lk);
}

FatKey 在这两种情况下都是由 const ref 传递的,它们都是模板类,它们都不是可复制构造的,但仍然只有其中一个有效。

我在这里错过了什么?

【问题讨论】:

标签: c++ templates c++14


【解决方案1】:

std::unique_ptr&lt;int&gt;int 都不涉及用户定义的类型;就 ADL 而言,它们关联的命名空间仅为 namespace std

当您使用包装器类型时,您拥有根命名空间(声明包装器的命名空间)的关联命名空间,这意味着 ADL 可以找到其中定义的免费 operator&lt;s。

确实,这是一件好事,因为它可以防止其他人编写自己的 operator&lt;(int*, std::unique_ptr&lt;int&gt; const&amp;),这可能与您的行为不同。

【讨论】:

  • 要清楚,实际上并不好,因为您不应该从标准库类型继承” OP 没有使用继承。除非有旧版本的问题。
  • @NicolBolas 哎呀,是的。修复。
【解决方案2】:

ecatmur 已经回答第一个示例由于 ADL 而无法运行。

我只想展示如何在不需要所有这些额外功能的情况下创建std::set

auto PtrCmp = [](std::unique_ptr<int> const & lhs,
    std::unique_ptr<int> const & rhs) {
  return lhs.get() < rhs.get();
};

auto orderedPtrSet = std::set<std::unique_ptr<int>, decltype(PtrCmp)>(PtrCmp);

注意:我知道这不是问题的真正答案,但发表评论有点太长了。在我看来,这对 OP 来说可能很有趣。

【讨论】:

  • 我对此投了反对票,原因有两个:默认构造的无状态 lambda 仅在 C++20 中引入,我的问题是关于通过身份而不是值比较 unique_ptrs 的透明比较器
  • @BalázsKovacsics 啊,我没有注意到我的编译器设置为 C++20。我也错过了你在比较指针本身。该示例现在可以正确比较并适用于 C++14。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-26
  • 1970-01-01
  • 1970-01-01
  • 2014-08-29
相关资源
最近更新 更多