我在std库中找到了std :: forward的以下实现:
// TEMPLATE FUNCTION forward
template<class _Ty> inline
constexpr _Ty&& forward(
typename remove_reference<_Ty>::type& _Arg) _NOEXCEPT
{ // forward an lvalue as either an lvalue or an rvalue
return (static_cast<_Ty&&>(_Arg));
}
template<class _Ty> inline
constexpr _Ty&& forward(
typename remove_reference<_Ty>::type&& _Arg) _NOEXCEPT
{ // forward an rvalue as an rvalue
static_assert(!is_lvalue_reference<_Ty>::value, "bad forward call");
return (static_cast<_Ty&&>(_Arg));
}
第一个功能显然有效,但是第二个功能我找不到有用的例子。 如果我尝试做这样的事情:
template<class _Ty> inline
constexpr _Ty&& my_forward(
typename std::remove_reference<_Ty>::type&& _Arg) _NOEXCEPT
{ // forward an rvalue as an rvalue
static_assert(!std::is_lvalue_reference<_Ty>::value, "bad forward call");
return (static_cast<_Ty&&>(_Arg));
}
template<typename T>
T getRValue()
{
return std::remove_reference<T>::type{};
}
template<typename T>
void setValue(T && i)
{
my_forward<T>(getRValue<T>());
}
int main()
{
int i = 1;
setValue(i);
}
检查第二个函数何时被调用,我收到错误:
Error C2664 '_Ty my_forward<T>(int &&) noexcept': cannot convert argument 1 from 'int' to 'int &&'
有人知道在哪种情况下会调用第二个重载函数(用我的术语my_forward)吗? 或者可能是一个很好的例子呢? 顺便说一句,我的编译器是MSVC 2015
谢谢,一切都求助!!
答案 0 :(得分:0)
int bad_forward_call() {
return std::forward<int&>(7);
}
这将调用该版本。
注意我将左值转发为左值。不允许。
如果getRValue
是参考类型,则T
无法获得右值。
答案 1 :(得分:0)
我找到了调用此函数的案例:
my_forward<int&>(8); // This calls forward(typename remove_reference<_Ty>::type&& _Arg)
But it won't compile 'cause we try convert rvalue to lvalue
my_forward<int&&>(8); // This calls forward(typename remove_reference<_Ty>::type&& _Arg)
But it compiles successfully
如果它对某人有用, std :: forward 的目的是将操作转发给另一个类或函数。
考虑以下示例:
template<typename T>
void precompute(T & t)
{
std::cout << "lvalue reference";
}
template<typename T,
std::enable_if_t<!std::is_reference<T>::value, bool> = true>
void precompute(T && t)
{
std::cout << "rvalue reference";
}
template<typename T>
void calculate(T && t)
{
precompute(t); // Every time called precompute(T & t)
}
或者像这样:
template<typename T>
void precompute(T & t)
{
std::cout << "lvalue reference";
}
template<typename T,
std::enable_if_t<!std::is_reference<T>::value, bool> = true>
void precompute(T && t)
{
std::cout << "rvalue reference";
}
template<typename T>
void calculate(T && t)
{
precompute(std::move(t)); // Every time called precompute(T && t)
}
正如您所看到的,我们遇到了问题!两个例子都没有让我们满意。
在第一个示例中,每次都会被称为左值函数,并且无法使用右值进行调用。
在第二个示例中,每次都会被称为 rvalue 函数,并且无法使用左值进行任何操作。
解决方案是将决策转发给被调用函数:
template<typename T>
void precompute(T & t)
{
std::cout << "lvalue reference";
}
template<typename T,
std::enable_if_t<!std::is_reference<T>::value, bool> = true>
void precompute(T && t)
{
std::cout << "rvalue reference";
}
template<typename T>
void calculate(T && t)
{
precompute(std::forward<T>(t)); // Will be called either precompute(T & t) or precompute(T && t) depends on type of t
}
在这种情况下,我们必须确保将其称为适当的版本。 这就是为什么我们转发(意思是:“请,检查t的类型,如果它是 rvalue - &gt;调用 rvalue 版本的函数,如果是左值 - &gt;调用左值版本的函数“)此操作被调用函数。