可变参数模板函数右值参数默默地将 C++ 移动到函数中

Variadic template function rvalue parameters silently moved C++ to the function

以下代码编译并打印: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 只接受右值引用?

为什么这是可能的,请参阅 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