【问题标题】:Variadic template function rvalue parameters silently moved C++ to the function可变模板函数右值参数默默地将 C++ 移动到函数中
【发布时间】:2020-11-13 16:10:26
【问题描述】:

以下代码编译并打印:move move。我宁愿它没有编译,因为 merge 采用右值引用并且我不会将 t1t2 移到它。

class A {
   public:
    A() = default;
    A(const A& other) { std::cout << "copy "; };
    A(A&& other) { std::cout << "move "; };
};

template <typename... TupleType>
auto merge(TupleType&&... tuples) {
    return std::tuple_cat(std::move(tuples)...);
}
int main() {
    std::tuple<int> t1{1};
    std::tuple<A> t2{A()};
    auto t3 = merge(t1, t2);
}

我不确定这里发生了什么以及为什么。此外,我认为这种行为是危险的:我在调用merge 时没有移动,但是t1t2 被移动了。

为什么允许这样做,我怎样才能让merge 只接受右值引用?

【问题讨论】:

  • TupleType&amp;&amp; 是转发引用,而不仅仅是右值引用,因为引用折叠规则。使用std::forward&lt;TupleType&gt;(tuples)... 而不是std::move(tuples)...,你会得到我所期望的你想要的行为。见this Q/Athis Q/A
  • @alterigel 答案应该属于答案框!

标签: c++ c++17 variadic-templates rvalue-reference fold-expression


【解决方案1】:

为什么会这样,请参阅Reference_collapsing

现在如果你想阻止你的函数接受lvalues,你可以使用下面的代码

#include <tuple>
#include <iostream>


class A {
public:
    A()  = default;
    A(const A& other) { std::cout << "\ncopy "; }
    A(A&& other)noexcept { std::cout << "\nmove "; }
};
template <typename... TupleType>
auto merge(TupleType&... tuples) = delete;

template <typename... TupleType>
auto merge(TupleType&&... tuples) {
    return std::tuple_cat(std::forward<TupleType>(tuples)...);
}

int main() {
    std::tuple<int> t1{1};
    std::tuple<A> t2{A()};
    // auto t3 = merge(t1, t2);//won't compile

    //compiles and gives the desired behavior move move
    auto t4 = merge(std::make_tuple(1), std::make_tuple(A{}));
}

Live

【讨论】:

    猜你喜欢
    • 2015-07-08
    • 2015-05-08
    • 2012-03-26
    • 2011-03-19
    • 1970-01-01
    • 2016-03-01
    • 1970-01-01
    • 2011-06-11
    • 1970-01-01
    相关资源
    最近更新 更多