从映射中返回与返回值类型匹配的值

4
我收到了以下错误。
In file included from /Users/james/ClionProjects/United States Computing Olympiad/graphs.cpp:2:
In file included from /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/string:439:
In file included from /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/algorithm:628:
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/memory:1673:31: error: no matching constructor for initialization of 'Vertex'
            ::new((void*)__p) _Up(_VSTD::forward<_Args>(__args)...);

以下是我代码的相关部分摘录:

class Vertex {
 public:
    int label;
    vector<Vertex> adjacent_vertices;
    Vertex(const int l) : label(l) { }
    Vertex(const int l, vector<Vertex> adjacents) : label(l), adjacent_vertices(adjacents) { }
    Vertex(const Vertex& other_vertex) : label(other_vertex.label), adjacent_vertices(other_vertex.adjacent_vertices){ }
};
class Graph {
 public:
    unordered_map<int, Vertex> vertices;
    protected:
    Vertex getmake_vertex(const int v) {
        if (vertices.find(v) == vertices.end() ) {
            // not found, make new vertex
            vertices[v] = Vertex(v);
        }
        return vertices[v];
    };
};

我已确认将其余所有内容注释后运行会导致编译器错误。有人能解释一下这是为什么,以及我该如何修复它吗?这里是完整的编译器输出。
3个回答

5
当你使用vertices[v] = Vertex(v);时,它必须在赋值之前为键v创建一个Vertex,但是Vertex没有默认构造函数。
你应该使用vertices.insert(make_pair(v, Vertex(v)))甚至vertices.emplace(v, Vertex(v))
这也适用于return vertices[v];。即使你和我都知道此时v已经有了值,但编译器不知道,仍然必须生成代码来潜在地创建一个值,这会导致错误。
将其设置为return vertices.find(v)->second;将修复该部分。无需检查并确保find值不是end,因为如果它不存在,我们刚刚把它放进去了。

1
如果你的类没有默认构造函数,那么这确实是你应该这样做的方式。 - emvee
@CrazyPython 如果你提供了一个 MCVE(http://stackoverflow.com/help/mcve),我就可以自己尝试一下,看看到底是什么有效的,但你没有提供,所以我不能。 - xaxxon
@xaxxon 我去掉了所有不必要的代码,并链接到错误这里,包括库导入、空的主方法和测试隔离错误。 - noɥʇʎԀʎzɐɹƆ
让我们在聊天中继续这个讨论。点击此处进入聊天室 - noɥʇʎԀʎzɐɹƆ
std::(unordered_)map并不是从“编写良好的语法”角度来看最有用的数据结构。multimap则更糟糕。 - xaxxon
显示剩余10条评论

1
使用operator[]需要你的mapped_type(在你的情况下是Vertex)可默认构造1,因为如果键不存在于映射中,它会插入一个默认构造1mapped_type。这是一个运行时决定,所以即使键实际上存在,你仍然需要在编译时具备默认构造函数。
在C++17中,请使用try_emplace
Vertex getmake_vertex(const int v) {
    return vertices.try_emplace(v, v).first->second;
}

否则,请使用insertemplace
Vertex getmake_vertex(const int v) {
    return vertices.insert({v, v}).first->second;
}

(如果你将Vertex(int)构造函数设置为explicit,那么你可能需要使用Vertex(v)。)

如果键已经在map中,则上述三种方法都不会插入。所有三个方法都返回一个指向具有指定键的元素的pair<iterator, bool>


1 不完全正确,但对我们的目的来说足够正确。


0

如果我正确地阅读了错误消息的这一部分,则需要Vertex的默认构造函数; 特别是这个:

需要2个参数,但未提供0个

/Users/james/ClionProjects/United States Computing Olympiad/graphs.cpp:14:5: note: candidate constructor not viable: requires single argument 'l', but no arguments were provided
    Vertex(const int l) : label(l) { }
    ^
/Users/james/ClionProjects/United States Computing Olympiad/graphs.cpp:16:5: note: candidate constructor not viable: requires single argument 'other_vertex', but no arguments were provided
    Vertex(const Vertex& other_vertex) : label(other_vertex.label), adjacent_vertices(other_vertex.adjacent_vertices){ }
    ^
/Users/james/ClionProjects/United States Computing Olympiad/graphs.cpp:15:5: note: candidate constructor not viable: requires 2 arguments, but 0 were provided
    Vertex(const int l, vector<Vertex> adjacents) : label(l), adjacent_vertices(adjacents) { }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接