C++ 使用通用参考实现正向功能
VS2013中C++ 使用通用参考实现正向功能,c++,c++11,C++,C++11,VS2013中std::forward的实现是 template<class _Ty> inline _Ty&& forward(typename remove_reference<_Ty>::type& _Arg) { // forward an lvalue return (static_cast<_Ty&&>(_Arg)); } template<class _Ty>
std::forward
的实现是
template<class _Ty> inline
_Ty&& forward(typename remove_reference<_Ty>::type& _Arg)
{ // forward an lvalue
return (static_cast<_Ty&&>(_Arg));
}
template<class _Ty> inline
_Ty&& forward(typename remove_reference<_Ty>::type&& _Arg) _NOEXCEPT
{ // forward anything
static_assert(!is_lvalue_reference<_Ty>::value, "bad forward call");
return (static_cast<_Ty&&>(_Arg));
}
模板内联
_Ty&&forward(类型名称删除\引用::类型和参数)
{//向前推进左值
返回(静态_cast(_Arg));
}
模板内联
_Ty&&forward(typename remove_reference::type&&u Arg)_NOEXCEPT
{//转发任何东西
静态断言(!is_lvalue_reference::value,“错误的前向调用”);
返回(静态_cast(_Arg));
}
一个版本用于左值引用,一个版本用于右值引用。为什么不为右值和左值引用使用通用引用:
template <typename T, typename U>
T&& Forward(U&& arg) {
return static_cast<T&&>(arg);
}
模板
T&&Forward(U&&arg){
返回静态_cast(arg);
}
您的版本不符合标准,因为如果T
是一个l值引用,则在右值上调用时要求不编译std::forward
。从[转发]
:
template <class T> T&& forward(typename remove_reference<T>::type& t) noexcept;
template <class T> T&& forward(typename remove_reference<T>::type&& t) noexcept;
模板T&&forward(typename remove_reference::type&T)无例外;
模板T&&forward(typename remove_reference::type&&T)无例外;
2返回:static\u cast(t)
3如果第二个表单是用左值引用类型实例化的,则程序的格式不正确
std::forward
以这种方式定义,以确保(某些)误用std::forward
不会编译。有关更多讨论,请参阅(尽管n2951也不使用这种确切形式)。我将对您在这里指出的问题进行一些扩展
如果您试图将新创建的右值绑定到l值引用,那么您的版本将引入一个挂起的引用
正如Mankarse所链接的,本文引用了这个案例,通过稍微简化,您可以用下面的代码对其进行总结
#include <iostream>
using namespace std;
template <typename T, typename U>
T&& Forward(U&& arg) {
return static_cast<T&&>(arg);
}
class Container
{
int data_;
public:
explicit Container(int data = 1) // Set the data variable
: data_(data) {}
~Container() {data_ = -1;} // When destructed, first set the data to -1
void test()
{
if (data_ <= 0)
std::cout << "OPS! A is destructed!\n";
else
std::cout << "A = " << data_ << '\n';
}
};
// This class has a reference to the data object
class Reference_To_Container_Wrapper
{
const Container& a_;
public:
explicit Reference_To_Container_Wrapper(const Container& a) : a_(a) {}
// (I) This line causes problems! This "Container" returned will be destroyed and cause troubles!
const Container get() const {return a_;} // Build a new Container out of the reference and return it
};
template <class T>
struct ReferenceContainer
{
T should_be_valid_lvalue_ref;
template <class U> // U = Reference_To_Container_Wrapper
ReferenceContainer(U&& u) :
// We store a l-value reference to a container, but the container is from line (I)
// and thus will soon get destroyed and we'll have a dangling reference
should_be_valid_lvalue_ref(Forward<T>(std::move(u).get())) {}
};
int main() {
Container a(42); // This lives happily with perfect valid data
ReferenceContainer<const Container&> rc( (Reference_To_Container_Wrapper(a)) ); // Parenthesis necessary otherwise most vexing parse will think this is a function pointer..
// rc now has a dangling reference
Container newContainer = rc.should_be_valid_lvalue_ref; // From reference to Container
newContainer.test();
return 0;
}
上面的方法很好用
FWIW,标准规定了§20.2.3中的重载。如果我始终正确使用forward函数,我的实现和标准实现之间有什么区别吗?@青云你可以使用自己的函数,但这意味着“我编写了一个函数,在某些情况下,可能会使程序崩溃”。如果你能确保你永远不会遇到这种情况,我相信没关系。但是由于标准保护您不受这些影响,并且检查是在编译时完成的。。我真的不明白重点。实际上,我想写一个
forwardNth
函数来转发参数包中的特定元素。除了正向通用引用参数外,它不会用于其他情况。另外:垂直滚动:(您遗漏了SFINAE检查,这让我很困惑:ReferenceContainer
ctor应该只接受右值。@dyp对不起:D我想让它更容易阅读(乍一看已经有点难了)
const Container& get() const {return a_;}