C++ 使用通用参考实现正向功能

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>

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));
    }
模板内联
_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_;}