首页 > 解决方案 > 是否可以在`std::forward`中省略模板参数?

问题描述

的标准签名std::forward是:

template<typename T>
constexpr T&& forward(std::remove_reference_t<T>&) noexcept;
template<typename T>
constexpr T&& forward(std::remove_reference_t<T>&&) noexcept;

因为参数类型不是T直接的,所以我们应该在使用时指定模板参数std::forward

template<typename... Args>
void foo(Args&&... args)
{
    bar(std::forward<Args>(args)...);
}

然而,有时模板参数并不像Args. auto&&是一个案例:

auto&& vec = foo();
bar(std::forward<decltype(vec)>(vec));

您还可以想象更复杂的模板参数类型std::forward。无论如何,直觉上std::forward应该知道是什么T,但实际上并不知道。

所以我的想法是省略<Args><decltype(vec)>不管它们多么简单。这是我的实现:

#include <type_traits>

template<typename T>
std::add_rvalue_reference_t<std::enable_if_t<!std::is_lvalue_reference<T>::value, T>>
my_forward(T&& obj)
{
    return std::move(obj);
}

template<typename T>
T& my_forward(T& obj)
{
    return obj;
}

int main()
{
    my_forward(1); // my_forward(int&&)
    int i = 2;
    my_forward(i); // my_forward(int&)
    const int j = 3;
    my_forward(j); // my_forward(const int&)
}

什么时候obj是右值引用,例如int&&,选择第一个重载是因为Tis int,其is_lvalue_reference为false;

obj例如,当是左值引用时,const int&选择第二个重载是因为Tisconst int&而第一个重载是 SFINAE-ed out。

如果我的实现是可行的,为什么std::forward仍然需要<T>?(所以我的一定是不可行的。)

如果不是,有什么问题?还有一个问题,是否可以省略模板参数std::forward

标签: c++c++11templates

解决方案


有问题的情况是当您传递右值引用类型但不属于右值值类别的东西时:

int && ir{::std::move(i)};
my_forward(ir); // my_forward(int&)

将类型传递给std::forward将确保右值引用类型的参数将作为右值进一步移动。


推荐阅读