C++ std::forward<T> 对比 static_cast<T>
C++ std::forward<T> vs static_cast<T>
据我了解,std::forward<T>(x)
等同于 static_cast<T&&>(x)
。
但是据我所见,static_cast<T>(x)
似乎做了同样的事情,如下所示code
因此我的问题是为什么 std::forward<T>
实现为 static_cast<T&&>(x)
,而不是 static_cast<T>(x)
,如果两者具有相同的效果?
因为完美转发允许同时传递 r 值引用 和 l 值引用 。这是通过 reference collapsing:
完成的
T = int --> T&& = int&&
T = int& --> T&& = int& && = int&
T = int&& --> T&& = int&& && = int&&
在您使用 static_cast<T>
的示例中,您只是丢失了 r 值引用。它适用于基本类型(因为传递 int
通常是复制一个 CPU 寄存器值),但对于复杂类型来说很糟糕,因为它会导致通过复制 ctors 创建临时对象。
如果 T&&
是一个右值引用,那么 T
是一个值,那么 static_cast<T>
使 copy 不是右值引用。
该副本将绑定到右值引用(就像引用一样),但是 copy/move 构造函数可能会被不必要地调用,它不是省略的候选对象。
static_cast<T&&>
将同时转换为右值引用。
它们在其他方面是相同的。
我同意 Yakk 的观点,但它比那更糟。
void foo(const std::vector<int> &vec);
template<typename T>
void callFoo(T &&data)
{
foo(static_cast<T>(data));
}
int main()
{
callFoo(std::vector<int>{/*...*/});
}
这将始终创建一个副本。向量 未 移动,因为 data
作为表达式是类型 std::vector<int>
的左值,即使替换的类型是 std::vector<int>&&
。请注意 T
是 std::vector<int>
,而不是 std::vector<int> &&
。这个故事的寓意:使用标准库,它做了正确的事情,而且名称 forward
也比 static_cast<something>
.
更能抓住意图
据我了解,std::forward<T>(x)
等同于 static_cast<T&&>(x)
。
但是据我所见,static_cast<T>(x)
似乎做了同样的事情,如下所示code
因此我的问题是为什么 std::forward<T>
实现为 static_cast<T&&>(x)
,而不是 static_cast<T>(x)
,如果两者具有相同的效果?
因为完美转发允许同时传递 r 值引用 和 l 值引用 。这是通过 reference collapsing:
完成的T = int --> T&& = int&&
T = int& --> T&& = int& && = int&
T = int&& --> T&& = int&& && = int&&
在您使用 static_cast<T>
的示例中,您只是丢失了 r 值引用。它适用于基本类型(因为传递 int
通常是复制一个 CPU 寄存器值),但对于复杂类型来说很糟糕,因为它会导致通过复制 ctors 创建临时对象。
如果 T&&
是一个右值引用,那么 T
是一个值,那么 static_cast<T>
使 copy 不是右值引用。
该副本将绑定到右值引用(就像引用一样),但是 copy/move 构造函数可能会被不必要地调用,它不是省略的候选对象。
static_cast<T&&>
将同时转换为右值引用。
它们在其他方面是相同的。
我同意 Yakk 的观点,但它比那更糟。
void foo(const std::vector<int> &vec);
template<typename T>
void callFoo(T &&data)
{
foo(static_cast<T>(data));
}
int main()
{
callFoo(std::vector<int>{/*...*/});
}
这将始终创建一个副本。向量 未 移动,因为 data
作为表达式是类型 std::vector<int>
的左值,即使替换的类型是 std::vector<int>&&
。请注意 T
是 std::vector<int>
,而不是 std::vector<int> &&
。这个故事的寓意:使用标准库,它做了正确的事情,而且名称 forward
也比 static_cast<something>
.