C++ 移动作为常量引用参数传递的类的成员

C++ 移动作为常量引用参数传递的类的成员,c++,c++11,move-semantics,stdtuple,C++,C++11,Move Semantics,Stdtuple,考虑到: template <typename... Args> ResourceHolder& operator+=(const ResourceInserter<Key, Args...>& inserter) { if constexpr (sizeof...(Args) == 0) { insert(std::move(inserter.key), std::move(inserter.fil

考虑到:

template <typename... Args>
ResourceHolder& operator+=(const ResourceInserter<Key, Args...>& inserter) {

    if constexpr (sizeof...(Args) == 0) {
        insert(std::move(inserter.key),
               std::move(inserter.fileName));
    } else {
        insert(std::move(inserter.key),
               std::move(inserter.fileName),
               std::move(std::get<Args...>(inserter.tuple)));
    }

    return *this;
}
你认为这是移动语义的正确用法吗


ResourceInserter的插入器实例作为常量引用传递。

移动常量对象通常是一个简单的副本,除非您重载Objectconst对象&&因此您对std::move的使用似乎毫无用处

如果ResourceInserter的成员是非常量引用,
您的const resourceinerter&具有误导性,您的移动实际上会发生。

移动const对象通常是一个简单的副本,除非您重载Objectconst对象&因此您对std::move的使用似乎没有用

如果ResourceInserter的成员是非常量引用, 您的const ResourceInserter&具有误导性,您的移动将实际发生。

您正在强制转换为const Key&&等。Key::keycont Key&&通常无法执行任何有用的操作,因此您将进行复制

您可能需要一对重载

template <typename... Args>
ResourceHolder& operator+=(const ResourceInserter<Key, Args...>& inserter) {

    if constexpr (sizeof...(Args) == 0) {
        insert(inserter.key,
               inserter.fileName);
    } else {
        insert(inserter.key,
               inserter.fileName,
               std::get<Args...>(inserter.tuple));
    }

    return *this;
}

template <typename... Args>
ResourceHolder& operator+=(ResourceInserter<Key, Args...>&& inserter) {

    if constexpr (sizeof...(Args) == 0) {
        insert(std::move(inserter.key),
               std::move(inserter.fileName));
    } else {
        insert(std::move(inserter.key),
               std::move(inserter.fileName),
               std::move(std::get<Args...>(inserter.tuple)));
    }

    return *this;
}
从右值插入器的成员移动的位置

您正在强制转换为const Key&&等。Key::keycont Key&&通常无法执行任何有用的操作,因此您将进行复制

您可能需要一对重载

template <typename... Args>
ResourceHolder& operator+=(const ResourceInserter<Key, Args...>& inserter) {

    if constexpr (sizeof...(Args) == 0) {
        insert(inserter.key,
               inserter.fileName);
    } else {
        insert(inserter.key,
               inserter.fileName,
               std::get<Args...>(inserter.tuple));
    }

    return *this;
}

template <typename... Args>
ResourceHolder& operator+=(ResourceInserter<Key, Args...>&& inserter) {

    if constexpr (sizeof...(Args) == 0) {
        insert(std::move(inserter.key),
               std::move(inserter.fileName));
    } else {
        insert(std::move(inserter.key),
               std::move(inserter.fileName),
               std::move(std::get<Args...>(inserter.tuple)));
    }

    return *this;
}
如果您从右值插入器的成员移动,而不是从其名称移动,则实际上不会移动任何内容。它只告诉编译器尝试移动,即通过将对象t强制转换为右值引用类型[更具体地说,通过生成]来指示对象t可以从中移动

但是,您的类没有接受常量插入器的构造函数&&,它将使用您的类的隐式或显式,并安全地复制。没有危险,就没有陷阱。如果出于任何原因禁用了复制构造函数,则会出现编译错误

试试这个:

#include <iostream>
struct Test {
   Test() { }
   Test(const Test& ) { std::cout << "COPY" << std::endl; }
   Test(Test&&)       { std::cout << "MOVE" << std::endl; }
};

int main() 
{
    const Test t;
    Test t2 = std::move(t);
    return 0;
}
打印副本,而不是移动。

与其名称相反,实际上不会移动任何东西。它只告诉编译器尝试移动,即通过将对象t强制转换为右值引用类型[更具体地说,通过生成]来指示对象t可以从中移动

但是,您的类没有接受常量插入器的构造函数&&,它将使用您的类的隐式或显式,并安全地复制。没有危险,就没有陷阱。如果出于任何原因禁用了复制构造函数,则会出现编译错误

试试这个:

#include <iostream>
struct Test {
   Test() { }
   Test(const Test& ) { std::cout << "COPY" << std::endl; }
   Test(Test&&)       { std::cout << "MOVE" << std::endl; }
};

int main() 
{
    const Test t;
    Test t2 = std::move(t);
    return 0;
}

打印副本,而不是移动。

移动常量对象通常是一个简单的副本。移动常量对象通常是一个简单的副本。