可以将 std::map 创建为右值吗?

Possible to create std::map as rvalue?

我不确定这是我的 C++ 语法错误,还是根本无法完成。

我想定义一个 class,它将 std::map 作为构造函数参数。然后我想通过传递 "temporary"(适合称呼此 "rvalue"?)std::map 来创建 class 的实例。 IE。我不想创建左值 std::map 然后将其传递给构造函数。

这能实现吗?我尝试了以下(注释行显示失败的尝试)

#include <map>
#include <string>
#include <iostream>

class Test
{
    public:
        Test(std::map<int,char>& rMap)
        {
            std::map<int,char>::iterator iter;

            for (iter = rMap.begin(); iter != rMap.end(); ++iter)
            {
                mMap[iter->first] = mMap[iter->second];
            }
        }
        virtual ~Test(){}

    protected:
        std::map<int, char> mMap;
};

int main()
{
    std::cout << "Hello world!" << std::endl;

    //Test test({1,'a'});                   // Compile error.
    //Test test(std::map<int,char>(1,'a')); // Also compile error.
    //Test test(std::map<int,char>{1,'a'}); // Yet again compile error.

    return 0;
}

这是我的编译器:

g++ (GCC) 4.4.7 20120313 (Red Hat 4.4.7-11)

可以根据要求发布编译错误,但我不确定如果我的问题是语法问题,它们是否有用。

谢谢。

是的,但是您的构造函数采用左值引用。它必须是对 const 的引用或右值引用。

就像任何其他类型一样。

Test(std::map<int, char> rMap) : mMap(std::move(rMap)) {}

Test(std::map<int, char>&& rMap) : mMap(std::move(rMap)) {}

Test(const std::map<int, char>& rMap) : mMap(rMap) {}

临时无法绑定到非 const 左值引用。

并将其用作

Test test({{1,'a'}});
Test test2({{1,'a'}, {2, 'b'}});
#include <map>

class Test {
public:
    Test(std::map<int,char> const& cMap)
    {
        std::map<int,char>::const_iterator iter;
        for (iter = cMap.cbegin(); iter != cMap.cend(); ++iter)
        {
            mMap[iter->first] = mMap[iter->second];
        }
    }
    virtual ~Test() { }
protected:
    std::map<int, char> mMap;
};

int main() {
    Test test(std::map<int,char>({{1,'a'}, {2, 'b'}}));
    return 0;
}

一些解释:

  1. 如果您想将临时对象(如std::map<int,char>())传递给它,您需要Test(T)Test(const T&)Test(T&&) 构造函数。不要忘记 T&& 构造函数的用途。如果有疑问,请不要使用它们。
  2. 如果您使用 const std::vector/map/list/...,则不能使用 .begin().end() 遍历元素 - 使用 .cbegin() 和.cend()。此外,使用 auto 会变得更容易。试试

    for (auto iter = rMap.cbegin(); iter != rMap.cend(); ++iter)
    

    改为

    std::map<int,char>::const_iterator iter;
    for (iter = rMap.cbegin(); iter != rMap.cend(); ++iter)
    
  3. 要初始化 std::map 使用 "double-bracket" 初始化器,如 {{1,'a'}, {2, 'b'}} -- {{key, value}, {second_key, second_value}, ...} 此构造可用,因为

    1) std::map 有这个构造函数:

    map( std::initializer_list<value_type> init,
         const Compare& comp = Compare(),
         const Allocator& alloc = Allocator() );
    // see http://en.cppreference.com/w/cpp/container/map/map
    

    2) 内括号 {1,'a'} 被解释为 value_type 构造函数调用。 std::map<int, char>value_typestd::pair<int, char>.

P. S. 不要忘记 std::map<int,char>()std::map<int,char>{} 构造函数调用是相等的。这意味着您可以去掉前括号:std::map<int,char>({{1,'a'},{2,'b'}}) --> std::map<int,char>{{1,'a'},{2,'b'}}

你应该使用:

class Test
{
public:
    Test(const std::map<int,char>& rMap) : mMap(rMap)
    {}
    Test(std::map<int,char>&& rMap) : mMap(std::move(rMap))
    {}
    virtual ~Test(){}
protected:
    std::map<int, char> mMap;
};

这提供了两个构造函数:一个采用 const 左值引用并将其内容复制到 mMap 中,另一个采用右值引用并将其内容移动到 mMap 中。这允许您使用命名的 std::map 或临时的 Test 构造一个实例:

int main()
{
    std::map<int,char> m{{1, 'a'}, {2,'b'}};
    Test t1{m};
    Test t2{{{1, 'a'}, {2, 'b'}}};
}

这可以让您尽可能避免不必要的副本,但仍然可以让您在需要时制作 map 的副本。