使用通用引用实现转发功能

时间:2014-05-31 11:23:31

标签: 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> 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));
    }

左值参考的一个版本,右值参考的一个版本。为什么不对rvalue和左值引用使用通用引用:

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

2 个答案:

答案 0 :(得分:4)

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

     

3如果第二个表单用左值引用类型实例化,则程序格式不正确。

std::forward以这种方式定义,以确保std::forward的(某些)误用不会编译。有关更多讨论,请参阅n2951(尽管即使n2951也不使用此确切形式)。

答案 1 :(得分:3)

我正在扩展你在这里指出的问题。

如果您尝试将新创建的右值绑定到l值引用,那么您的版本将引入引用悬空大小写。

当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被破坏!”

如果您只是添加“&amp;”在行

const Container& get() const {return a_;}

上述工作正常。

http://ideone.com/SyUXss