特定类型完美转发

问题描述 投票:0回答:2

在编写线程安全

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
或对其的引用,或者使用概念。

c++ perfect-forwarding function-templates forwarding-reference
2个回答
2
投票

你可以断言它:

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

您也可以使用

is_convertible
代替
is_same
,这样效果会更自然。


1
投票

我在多个版本中重复

@Ayxan Haqverdili
的例子。另请注意,因为您提到您想要一个标准方法来解决这个问题,所以
C++20
概念现在是标准方法。除非您编写的代码需要与旧语言版本兼容,否则应该使用它。主要原因是它清楚、简洁地记录了声明站点的功能要求。这甚至比
static_assert
更有说服力,并且允许重载而不是直接失败。
std::enable_if
只是设置要求的旧方法。

内联概念

template <class T>
    requires std::convertible_to<T, value_type>
void push(T &&value);

定制概念

这让您可以使用方便的参数

auto

template <class T, class U>
concept ForwardType = std::convertible_to<T, U>

void push(ForwardType<value_type> auto &&value);

使用
std::enable_if

这应该与 C++11 兼容。

template <class T>
std::enable_if_t<std::is_convertible_v<T>> push(T &&value);
© www.soinside.com 2019 - 2024. All rights reserved.