# 原地构造
请使用 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)帮你改成最合理的写法。