统一常量 T& 和 T&& 重载

unifying const T& and T&& overloads

本文关键字:重载 常量      更新时间:2023-10-16

我有以下两个函数模板重载:

template<typename T>
optional<T> some(const T& x)
{
    return optional<T>(x);
}
template<typename T>
typename std::enable_if<std::is_rvalue_reference<T&&>::value, optional<T> >::type
some(T&& x)
{
    return optional<T>(std::move(x));
}

我第一次尝试通过完美转发统一重载失败了:

template<typename T>
optional<T> some(T&& x)
{
    return optional<T>(std::forward<T>(x));
}
error: forming pointer to reference type 'const std::basic_string<char>&'

就像我的第二次尝试一样:

template<typename T>
optional<typename std::remove_reference<T>::type> some(T&& x)
{
    return optional<typename std::remove_reference<T>::type>(std::forward<T>(x));
}
error: no matching function for call to
'std::basic_string<char>::basic_string(gpa::optional<const std::basic_string<char> >)'

有没有一种干净的方法来统一过载,或者我应该忍受它们?

我不熟悉你的optional,但也许你需要补充:

typename remove_const< ... >::type

在你的remove_reference周围有两个地方。 (因为您的 2 重载解决方案的第一次重载 - 我假设它通过了您的所有测试 - 在声明 optional<T> 时有效地执行了remove_const)。

通常,执行此操作的最佳方法是按值获取对象,并让调用方决定是复制还是移动它:

template<typename T>
optional<T> some(T x)
{
    return optional<T>(std::move(x));
}

如果调用方使用临时调用它或对其值使用 std::move,则会移动它。否则,它将被复制。

是的,这确实意味着您将执行一个额外的移动(如果移动与复制相同,则意味着执行两个副本)。如果这对您来说是一个重大的性能问题,则必须使用两个重载实现。