代码之家  ›  专栏  ›  技术社区  ›  bobobobo

为什么'std::make_tuple'需要移动语义?

  •  0
  • bobobobo  · 技术社区  · 3 年前

    我认为这是一个相当有意识的设计决定,创造一个 std::tuple std::make_tuple 需要右值引用参数(类型 T&& ).

    然而,这意味着 move semantics (std::move is little more than a cast to T&& ) 对于对象类型,我对构建 std::tuple 总是要求这样。

    int x = 7, y = 5;
    std::tuple<int, int> fraction = make_tuple<int, int>( x, y ); // fails
    

    关于上述内容,编译器说:

    错误C2664:'std::tuple<int,int>std::make_tuple<int,int>(国际,国际):无法将参数1从“int”转换为“int&&'

    消息:无法将左值绑定到右值引用

    你可以做一个 std::tuple 如果不使用,从左值看没有问题 make_tuple :

    std::tuple<int, int> fraction = { x, y }; // ok
    

    我的问题是,为什么会这样?

    0 回复  |  直到 3 年前
        1
  •  6
  •   Captain Hatteras    3 年前

    std::make_tuple 不将右值引用带到 T ,与表面相反;它普遍引用 T ( T&& ).如果通用参考对你来说是新的,让我解释一下。

    make_tuple 大致如下所示:

    template<typename... Ts>
    std::tuple<Ts...> make_tuple(Ts&&... ts){ 
        // ... 
    }
    

    制造元组 这样地:

    template<typename T>
    std::tuple<T> make_tuple(T&& t){ 
        // ... 
    }
    

    制造元组 传递了一个右值(比如 int&& ),为 T int 制造元组 T (b)现在看起来是这样的:

    std::tuple<int> make_tuple(int&& t){ 
        // ... 
    }
    

    这里是事情变得混乱的地方:如果 传递的是左值 int 可以推断为?编译器推断 T int& 使用了一种叫做 reference collapsing .

    引用折叠基本上表示,如果编译器形成对引用的引用,并且其中一个引用是左值引用,则生成的引用是左值引用。否则,它是一个右值引用。

    定义 制造元组 (有 T (b)现在看起来是这样的:

    std::tuple<int&> make_tuple(int& && t){ 
        // ... 
    }
    

    它崩溃为:

    std::tuple<int&> make_tuple(int& t){ 
        // ... 
    }
    

    那么,回到你失败的例子:

    std::tuple<int, int> fraction = make_tuple<int, int>( x, y );
    

    让我们看看是什么 看起来像:

    // since you explicitly called make_tuple<int,int>(), then no deduction occurs
    std::tuple<int,int> make_tuple(int&& t1, int&& t2){ // Error! rvalue reference cannot bind to lvalue
        // ... 
    }
    

    现在 很明显,为什么你的例子不起作用。由于没有发生引用崩溃,因此 T&& 国际及& .

    auto fraction = std::make_tuple(x,y);
    

    我希望我能解释清楚。