在 std::tie 中使用 std::weak_ptr::lock()

Using std::weak_ptr::lock() in std::tie

本文关键字:std ptr lock tie weak      更新时间:2023-10-16

我有一个包含两个弱指针的结构,我希望使用 std::tie 按字典顺序比较这个结构。但是,我遇到了一个奇怪的问题,我意识到我不能使用 std::weak_ptr::lock(( 作为 std::tie 的参数。 示例代码:

struct S {
S(std::shared_ptr<int>& f, std::shared_ptr<int>& s) {
first = f;
second = s;
}
bool operator<(const S& rhs) const {
return std::tie(first.lock(), second.lock()) < std::tie(rhs.first.lock(), rhs.second.lock());
}
std::weak_ptr<int> first, second;
};

这样做会导致编译错误,代码为E0304no instance of function template "std::tie" matches the argument list

但是,如果我创建新的std::shared_ptr对象并将它们设置为 std::weak_ptr::lock(( 的值,然后比较它们,一切正常:

struct S {
S(std::shared_ptr<int>& f, std::shared_ptr<int>& s) {
first = f;
second = s;
}
bool operator<(const S& rhs) const {
// creating shared_ptrs and assigning them the value of std::weak_ptr::lock()
std::shared_ptr<int> 
f = first.lock(), s = second.lock(),
rf = rhs.first.lock(), rs = rhs.second.lock();
// compare those shared_ptrs
return std::tie(f, s) < std::tie(rf, rs);
}
std::weak_ptr<int> first, second;
};
int main() {
std::shared_ptr<int> 
a(new int(10)),
b(new int(5));
// just two S initializations
S foo(a, b);
S bar(b, a);
if (foo < bar) {
std::cout << "Foo is less than Bar";
}
else {
std::cout << "Otherwise";
}
}

输出:Foo is less than Bar

为什么会这样?谢谢!

std::tie通过引用接收参数,因为它从它们构建了一个引用元组。临时,如lock()返回的std::shared_ptr,不能绑定到引用。创建单独的变量为引用提供了要绑定的内容。

std::tie仅适用于左值,创建返回类型,如std::tuple<T1&, T2&>lock()成员函数按值返回shared_ptr,因此表达式是右值,不能与std::tie一起使用。

您可以通过编写std::forward_as_tuple来更普遍地使用相同的元组词典编纂技巧:

return std::forward_as_tuple(first.lock(), second.lock()) < 
std::forward_as_tuple(rhs.first.lock(), rhs.second.lock());

这些forward_as_tuple调用的返回类型将为std::tuple<std::shared_ptr<int>&&, std::shared_ptr<int>&&>forward_as_tuple通常比tie更危险,因为它在某些用途中可以创建没有编译器警告的悬空引用,但在这里它是安全的,因为tuple对象是临时的,在operator<评估后不会使用。