# 原地构造 请使用 AI 工具查询 `emplace()` 的用法。 # 元素为结构体时调用 `emplace` 报错 对,你这个报错是**标准版本的问题**,锅在我这边示例没说清楚,先跟你道个歉 🙇‍♂️。 --- ## 1. 为什么 `emplace_back(3, 4)` 会报错? 你的代码大致是这样的(和我给的例 2 一样): ```cpp #include <vector> using namespace std; struct Node { int x; int y; }; int main() { vector<Node> v; v.push_back(Node{1, 2}); // OK v.emplace_back(3, 4); // ❌ 在 C++17 下会报错 } ``` 在 C++17(`-std=c++17` / 默认 `gnu++17`)里,`Node` 是一个**聚合类型 (aggregate)**, 它只有这些构造函数: - 默认构造 `Node()` - 拷贝构造 `Node(const Node&)` - 移动构造 `Node(Node&&)` **没有** `Node(int, int)` 这样的构造函数。 而 `emplace_back(3, 4)` 最终会在内部做类似的事情: ```cpp ::new(p) Node(3, 4); // 用括号做“直接初始化” ``` 在 C++17 中,用括号初始化聚合类型(`Node(3, 4)`)是不允许的, 编译器就会报: > no matching function for call to 'Node::Node(int, int)' 也就是你看到的那一串模板展开后的错误。 > ✅ 在 C++20 之后引入了“括号聚合初始化”(parenthesized aggregate initialization), > `Node n(1, 2);` 或 `emplace_back(1, 2);` 才变成合法。 > 但你现在用的是 GCC 13 的 C++17 模式,所以会报错。 --- ## 2. 在 C++17 下的正确写法 ### 写法 A:给结构体显式加一个构造函数(推荐) ```cpp #include <iostream> #include <vector> using namespace std; struct Node { int x; int y; Node(int x_, int y_) : x(x_), y(y_) {} // 显式构造函数 }; int main() { vector<Node> v; v.emplace_back(1, 2); // 直接用参数在 vector 里构造 Node(1, 2) v.emplace_back(3, 4); // 同上 for (auto &n : v) { cout << n.x << " " << n.y << "\n"; } } ``` 这样 `emplace_back(1, 2)` 就能正确匹配到 `Node(int, int)` 构造函数,在 C++17 没问题。 --- ### 写法 B:仍然用“聚合初始化”,但参数用大括号包起来 如果你不想写构造函数: ```cpp #include <vector> using namespace std; struct Node { int x; int y; }; int main() { vector<Node> v; v.push_back(Node{1, 2}); // OK v.emplace_back(Node{3, 4}); // 也能编译通过 v.emplace_back(Node{5, 6}); // 依然 OK // 或者: v.emplace_back(Node{7, 8}); // 参数是一个 Node 临时对象 return 0; } ``` 注意这里: - `emplace_back(Node{3, 4})` 传进去的其实是一个 **已经构造好的 `Node` 对象**; - 这和 `push_back(Node{3, 4})` 在效果上几乎没区别: 都是先构造临时 `Node`,然后在容器里移动/拷贝。 也就是说,在这种“纯聚合 struct + C++17”的情况下,`emplace_back(Node{...})` 用得好处并不明显。 --- ## 3. 如果你切到 C++20 如果你用: ```bash g++ -std=c++20 tttt.cpp ``` 并且编译器完全实现了 C++20 的这部分特性,那么原来的代码: ```cpp struct Node { int x; int y; }; vector<Node> v; v.emplace_back(3, 4); // 在 C++20 中是合法的(括号聚合初始化) ``` 就是可以通过编译的。 --- ## 4. 小结一下关键点 - 在 **C++17** 下: - 聚合类型(只有成员,没有自己写构造函数的 struct)**不能**用 `Type(1,2)` 这种括号形式做聚合初始化; - 所以 `emplace_back(3, 4)` 会找不到 `Node(int, int)`,编译错误; - 解决办法: - 要么给 struct 写一个构造函数 `Node(int,int)`; - 要么改成 `emplace_back(Node{3, 4});`,但这就和 `push_back(Node{3,4})` 差不太多。 - 在 **C++20 及之后**: - 标准允许“括号聚合初始化”,`Node n(1,2);` 和 `emplace_back(1,2);` 才变得合法。 如果你愿意,可以把你现在的那段完整代码贴出来,我可以按你当前使用的标准(C++17 / C++20)帮你改成最合理的写法。