Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/129.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ std::forward是否有使用prvalue的用例?_C++_C++11_Move Semantics_Rvalue Reference - Fatal编程技术网

C++ std::forward是否有使用prvalue的用例?

C++ std::forward是否有使用prvalue的用例?,c++,c++11,move-semantics,rvalue-reference,C++,C++11,Move Semantics,Rvalue Reference,std::forward最常见的用法是完美地转发转发(通用)引用,如 template<typename T> void f(T&& param) { g(std::forward<T>(param)); // perfect forward to g } 有人能告诉我为什么rvalue过载吗?我看不到任何用例。如果要将右值传递给函数,可以按原样传递,无需对其应用std::forward 这与std::move不同,在这里我明白了为什么人们还需要

std::forward
最常见的用法是完美地转发转发(通用)引用,如

template<typename T>
void f(T&& param)
{
    g(std::forward<T>(param)); // perfect forward to g
}
有人能告诉我为什么
rvalue
过载吗?我看不到任何用例。如果要将右值传递给函数,可以按原样传递,无需对其应用
std::forward

这与
std::move
不同,在这里我明白了为什么人们还需要
rvalue
重载:您可能需要处理不知道要传递什么并且希望无条件支持移动语义的通用代码,例如


编辑为了澄清这个问题,我想问一下为什么必要,以及它的一个用例。

这个答案是为了回答@vsoftco的评论


@DarioOO谢谢你的链接。你能写一个简洁的答案吗?从您的示例中,我仍然不清楚为什么还需要为右值定义std::forward

简而言之:

因为没有右值专门化,下面的代码将无法编译

#include <utility>
#include <vector>
using namespace std;

class Library
{
    vector<int> b;
public:
    // hi! only rvalue here :)
    Library( vector<int>&& a):b(std::move(a)){

    }
};

int main() 
{
    vector<int> v;
    v.push_back(1);
    A a( forward<vector<int>>(v));
    return 0;
}
如果你移动那个元素

vector<int> v;
v.push_back(1);
A a( std::move(v)); //what happens here? just moved
std::cout<<v[0];  // OUCH! out of bounds exception
向量v; v、 推回(1); A(std::move(v))//这里发生了什么?刚搬家
std::cout我以前一直盯着这个问题,读过霍华德·希南特的链接,经过一个小时的思考,我无法完全理解它。现在我正在寻找答案,五分钟内就得到了答案。(编辑:得到的答案太慷慨了,因为Hinnant的链接有答案。我的意思是我理解了,并且能够用更简单的方式解释,希望有人会觉得有用)

基本上,这允许您根据传入的类型在某些情况下使用泛型。考虑这个代码:

#include <utility>
#include <vector>
#include <iostream>
using namespace std;

class GoodBye
{
  double b;
 public:
  GoodBye( double&& a):b(std::move(a)){ std::cerr << "move"; }
  GoodBye( const double& a):b(a){ std::cerr << "copy"; }
};

struct Hello {
  double m_x;

  double & get()  { return m_x; }
};

int main()
{
  Hello h;
  GoodBye a(std::forward<double>(std::move(h).get()));
  return 0;
}
假设在
main
中的代码中,
h
是Hello2的一个实例。现在,我们不再需要std::forward,因为对
std::move(h).get()的调用将返回一个右值。但是,假设代码是泛型的:

template <class T>
void func(T && h) {
  GoodBye a(std::forward<double>(std::forward<T>(h).get()));
}
模板
无效函数(T&h){
再见a(std::forward(std::forward(h.get()));
}
现在,当我们调用
func
时,我们希望它能够与
Hello
Hello2
一起正常工作,即我们希望触发移动。如果包含外部的
std::forward
,则只有当右值为
Hello
时才会发生这种情况,因此我们需要它。但是我们到了关键点。当我们将
Hello2
的右值传递给此函数时,get()的右值重载将已经返回右值双精度,因此
std::forward
实际上正在接受右值。因此,如果它没有,您将无法编写上述完全通用的代码


该死。

好吧,既然@vsoftco要求简洁的用例,这里有一个精练的版本(使用他的“my_forward”的想法来实际查看调用的重载)

我通过提供一个没有prvalue的代码示例来解释“用例”,该示例不会编译或表现出不同的行为(不管这是否真的有用)

我们有
std::forward

#include <iostream>

template <class T>
inline T&& my_forward(typename std::remove_reference<T>::type& t) noexcept
{
    std::cout<<"overload 1"<<std::endl;
    return static_cast<T&&>(t);
}

template <class T>
inline T&& my_forward(typename std::remove_reference<T>::type&& t) noexcept
{
    std::cout<<"overload 2"<<std::endl;
    static_assert(!std::is_lvalue_reference<T>::value,
              "Can not forward an rvalue as an lvalue.");
    return static_cast<T&&>(t);
}
你会得到:

  • 编译错误
  • 编译
  • 编撰
  • 编译

  • 如您所见,如果只使用两个
    forward
    重载中的一个,则基本上不会编译4个案例中的2个,而如果根本不使用
    forward
    ,则只会编译4个案例中的3个。

    存在将右值作为右值转发的用例。请参阅。这是为了防止右值作为左值转发,而不使用一组额外的enable_if条件吗?(见案例C)@wakjah如何将右值作为左值转发?如果调用
    f(prvalue)
    ,其中
    prvalue
    类似于
    get\u value()
    ,则传递一个
    rvalue
    ,无需转发它。也许我没有明白你的意思。案例B是答案。@DarioOO谢谢你的链接。你能写一个简洁的答案吗?从您的示例中,我仍然不清楚为什么还需要为右值定义
    std::forward
    。谢谢,顺便说一句,您应该拥有
    ,而不是
    A
    。我会想一想你的例子,特别是关于向前复制然后移动。好了,
    forward
    只是使用引用折叠规则进行强制转换。但无论如何,再次感谢,我会很快让你知道我的想法。好的,看这里:。我使用名为
    my_forward
    的实现更改了
    forward
    ,该实现仅适用于左值。您的代码仍然可以编译。但是,如果您查看,您会看到有两个重载:(1)和(2)。(2) 获取一个pr值。我的问题是为什么(2)是必要的,什么是用例?如您所见,您的代码使用仅为左值定义的
    my_forward
    。我问的有意义吗?在你的例子中,
    forward(v)
    std::move(v)
    相同(请参见声明和引用折叠规则)
    v
    本身仍然是一个左值(有一个名称)。事实上,我的代码使用了我想显示的第一个重载,你指的是另一个重载。这是analoug,但是对于第二个重载,您接受显式移动的内容(如果您删除第一个重载,那么代码将不会编译,除非您使用std::move显式移动,删除引用使仅使用第二个重载无法隐式移动)请看这里,如果答案是你的工作,为什么你的代码与我的答案相似?(更不用说你在我的回答中加入了
    之类的内容,但你没有使用它:/moves非常喜欢文案粘贴和编辑,所以为什么不直接编辑呢?)。除了表面上的问题,这一点并不相似。我最初复制并粘贴了您的代码到我的ide中,因为我很好奇。然后我找到了答案,修改了我已经在那里的代码。我没有编辑你的答案,因为它不正确,它不会是一个小修改
    template< typename Impl, typename... SmartPointers>
    static std::shared_ptr<void> 
        instancesFactoryFunction( priv::Context * ctx){
            return std::static_pointer_cast<void>( std::make_shared<Impl>(
    
                    std::forward< typename SmartPointers::pointerType>( 
                SmartPointers::resolve(ctx))... 
                )           );
    }
    
    #include <utility>
    #include <vector>
    #include <iostream>
    using namespace std;
    
    class GoodBye
    {
      double b;
     public:
      GoodBye( double&& a):b(std::move(a)){ std::cerr << "move"; }
      GoodBye( const double& a):b(a){ std::cerr << "copy"; }
    };
    
    struct Hello {
      double m_x;
    
      double & get()  { return m_x; }
    };
    
    int main()
    {
      Hello h;
      GoodBye a(std::forward<double>(std::move(h).get()));
      return 0;
    }
    
    struct Hello2 {
      double m_x;
    
      double & get() & { return m_x; }
      double && get() && { return std::move(m_x); }
    };
    
    template <class T>
    void func(T && h) {
      GoodBye a(std::forward<double>(std::forward<T>(h).get()));
    }
    
    #include <iostream>
    
    template <class T>
    inline T&& my_forward(typename std::remove_reference<T>::type& t) noexcept
    {
        std::cout<<"overload 1"<<std::endl;
        return static_cast<T&&>(t);
    }
    
    template <class T>
    inline T&& my_forward(typename std::remove_reference<T>::type&& t) noexcept
    {
        std::cout<<"overload 2"<<std::endl;
        static_assert(!std::is_lvalue_reference<T>::value,
                  "Can not forward an rvalue as an lvalue.");
        return static_cast<T&&>(t);
    }
    
    #include <vector>
    using namespace std;
    
    class Library
    {
        vector<int> b;
    public:
        // &&
        Library( vector<int>&& a):b(std::move(a)){
    
        }
    };
    
    int main() 
    {
        vector<int> v;
        v.push_back(1);
        Library a( my_forward<vector<int>>(v)); // &
        return 0;
    }
    
    #include <vector>
    using namespace std;
    
    class Library
    {
        vector<int> b;
    public:
        // &&
        Library( vector<int>&& a):b(std::move(a)){
    
        }
    };
    
    int main() 
    {
        vector<int> v;
        v.push_back(1);
        Library a( my_forward<vector<int>>(std::move(v))); //&&
        return 0;
    }
    
    #include <vector>
    using namespace std;
    
    class Library
    {
        vector<int> b;
    public:
        // &
        Library( vector<int> a):b(a){
    
        }
    };
    
    int main() 
    {
        vector<int> v;
        v.push_back(1);
        Library a( my_forward<vector<int>>(v)); // &
        return 0;
    }
    
    #include <vector>
    using namespace std;
    
    class Library
    {
        vector<int> b;
    public:
        // &
        Library( vector<int> a):b(a){
    
        }
    };
    
    int main() 
    {
        vector<int> v;
        v.push_back(1);
        Library a( my_forward<vector<int>>(std::move(v))); //&&
        return 0;
    }
    
    Library a( std::move(v));
    //and
    Library a( v);