使用通用引用实现前向函数

Implement a forward function using universal reference

本文关键字:函数 引用 实现      更新时间:2023-10-16

std::forward在VS2013中的实现为

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));
    }

左值引用一个版本,右值引用一个版本。为什么不对左值和右值都使用通用引用呢?

template <typename T, typename U>
T&& Forward(U&& arg) {
  return static_cast<T&&>(arg);
}

您的版本不符合标准,因为如果T是左值引用,则std::forward在使用右值调用时需要不编译。源自[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;

2返回:static_cast<T&&>(t) .

如果第二种形式是用左值引用类型实例化的,则程序是病态的。

这样定义

std::forward是为了确保(某些)误用std::forward不能编译。有关更多讨论,请参阅n2951(尽管即使n2951也不使用这种确切的形式)。

我对你在这里指出的问题进行了一点扩展。

如果试图将新创建的右值绑定到左值引用,您的版本将引入引用悬空情况。

正如Mankarse所链接的,n2951论文引用了这种情况,通过稍微简化,您可以用以下代码对其进行总结

#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;
}

输出"OPS!"A被销毁了!"

如果在

行中添加&
const Container& get() const {return a_;}

上面的工作很好。

http://ideone.com/SyUXss