【问题标题】:Perfect forwarding with a specific type特定类型的完美转发
【发布时间】: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&amp;&amp;)template &lt;typename T&gt; void foo(T&amp;&amp;) 的语法糖

标签: c++ templates perfect-forwarding


【解决方案1】:

你可以断言它:

template<typename T>
void push(T&& value)
{
    static_assert(is_same_v<remove_reference_t<T>, value_type>);
    // ...
}

您也可以使用is_convertible 代替is_same,这样它会更自然地工作。

【讨论】:

  • @NathanOliver 我试图立即删除答案并在我注意到它后立即编辑该部分,您仍然设法留下评论:-)
  • 我能说什么,我是忍者 ;) 您应该考虑使用std::is_convertible 而不是std::is_same,这样可以转换为value_type 的东西也被接受。
猜你喜欢
  • 2015-04-22
  • 2021-06-17
  • 2016-03-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-01-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多