【发布时间】:2020-07-27 20:48:29
【问题描述】:
在编写线程安全的std::stack 包装器时,我为push 做了以下两个重载:
void push(const value_type& value)
{
auto guard = std::scoped_lock{_mutex};
_stack.push(value);
_cv.notify_one();
}
void push(value_type&& value)
{
auto guard = std::scoped_lock{_mutex};
_stack.push(std::move(value));
_cv.notify_one();
}
它们几乎相同,只是一个采用 const 左值引用,一个采用右值引用。通常我会使用完美转发来处理这个问题(现在使用光荣的 C++20 缩写模板声明):
void push(auto&& value)
{
auto guard = std::scoped_lock{_mutex};
_stack.push(std::forward<decltype(value)>(value));
_cv.notify_one();
}
这里的问题是它接受任何类型,而它应该只接受 value_type 和对它的引用。
有什么标准方法可以解决这个问题吗?到目前为止,我想出了两个方法。要么使用std::enable_if 以某种方式检查模板类型是value_type 还是对其的引用,或者使用概念。
【问题讨论】:
-
你也可以使用
static_assert。或者你可以不打扰,因为如果值的类型不正确,push(...)本身将无法编译。 -
您提到的两种方法都不允许转换,例如对于 double push(0) 的值类型将不起作用。我自己没有更好的解决方案,我使用概念方法。
-
那么 auto&& 将处理左值和右值?我总是像落后 5 年......我可能会在 2025 年了解 C++20 的特性。
-
@wcochran
void foo(auto&&)是template <typename T> void foo(T&&)的语法糖
标签: c++ templates perfect-forwarding