C ++ : operator << 컴파일 실패
Aug 19 2020
C ++로 B- 트리를 코딩하고 있지만 오버로딩 operator<<
하면 컴파일에 실패합니다.
내 코드 :
#include <cassert>
#include <cstddef>
#include <iostream>
#include <memory>
#include <vector>
#include <utility>
template <typename T, std::size_t t>
class BTree;
template <typename T, std::size_t t>
std::ostream& operator<<(std::ostream&, const BTree<T, t>&);
template <typename T, std::size_t t>
std::ostream& operator<<(std::ostream& os, const typename BTree<T, t>::Node& node);
template <typename T, std::size_t t>
class BTree {
static_assert(t >= 2);
class Node {
std::size_t n = 0;
public:
bool leaf = true;
std::vector<T> key;
std::vector<std::unique_ptr<Node>> child;
void setN(std::size_t N) {
n = N;
key.resize(n);
if (!leaf) {
child.resize(n + 1);
}
}
[[nodiscard]] std::size_t getN() const {
return n;
}
[[nodiscard]] bool isFull() const {
return n == 2 * t - 1;
}
friend std::ostream& operator<< <T, t>(std::ostream& os, const BTree<T, t>::Node& node);
};
std::unique_ptr<Node> root;
std::pair<const Node*, std::size_t> Search(const Node* x, const T& k) const {
std::size_t i = 0;
while (i < x->getN() && k > x->key[i]) {
i++;
}
if (i < x->getN() && k == x->key[i]) {
return {x, i};
} else if (x->leaf) {
return {nullptr, 0};
} else {
return Search(x->child[i].get(), k);
}
}
void SplitChild(Node* x, std::size_t i) {
if (!x) {
return;
}
auto y = x->child[i].get();
if (!y) {
return;
}
assert(!x->isFull() && y->isFull());
auto z = std::make_unique<Node>();
z->leaf = y->leaf;
z->setN(t - 1);
for (std::size_t j = 0; j < t - 1; j++) {
z->key[j] = y->key[j + t];
}
if (!y->leaf) {
for (std::size_t j = 0; j < t; j++) {
z->child[j] = std::move(y->child[j + t]);
}
}
x->setN(x->getN() + 1);
for (std::size_t j = x->getN() + 1; j >= i + 1; j--) {
x->child[j + 1] = std::move(x->child[j]);
}
x->child[i + 1] = std::move(z);
for (std::size_t j = x->getN() + 1; j >= i + 1; j--) {
x->key[j] = x->key[j - 1];
}
x->key[i] = y->key[t];
y->setN(t - 1);
}
void InsertNonFull(Node* x, const T& k) {
std::size_t i = x->getN();
if (x->leaf) {
x->setN(i + 1);
while (i < x->getN() && k < x->key[i]) {
x->key[i + 1] = x->key[i];
i--;
}
x->key[i + 1] = k;
} else {
while (i < x->getN() && k < x->key[i]) {
i--;
}
i++;
if (x->child[i]->isFull()) {
SplitChild(x, i);
if (k > x->key[i]) {
i++;
}
}
InsertNonFull(x->child[i].get(), k);
}
}
public:
BTree() {
root = std::make_unique<Node>();
}
[[nodiscard]] std::pair<const Node*, std::size_t> Search(const T& k) const {
return Search(root.get(), k);
}
void Insert(const T& k) {
if (root->isFull()) {
auto s = std::make_unique<Node>();
s->leaf = false;
s->setN(0);
s->child[0] = std::move(root);
root = std::move(s);
SplitChild(root.get(), 0);
InsertNonFull(root.get(), k);
} else {
InsertNonFull(root.get(), k);
}
}
friend std::ostream& operator<<<> (std::ostream&, const BTree<T, t>&);
};
template <typename T, std::size_t t>
std::ostream& operator<<(std::ostream& os, const typename BTree<T, t>::Node& node) {
if (node->leaf) {
for (std::size_t i = 0; i < node->getN() - 1; i++) {
os << node->key[i] << ' ';
}
os << node->key[node->getN() - 1];
} else {
for (std::size_t i = 0; i < node->getN(); i++) {
os << *node->child[i] << ' ' << node->key[i] << ' ';
}
os << *node->child[node->getN()];
}
return os;
}
template <typename T, std::size_t t>
std::ostream& operator<<(std::ostream& os, const BTree<T, t>& bt) {
os << *(bt.root) << '\n';
return os;
}
int main() {
BTree<int, 2> tree;
tree.Insert(1);
std::cout << tree;
}
이것은 내 컴파일러의 불평의 첫 번째 줄입니다 (200 줄 이상이 있기 때문에 전체 오류 출력을 게시하지 않을 것입니다).
/mnt/c/Users/kim/CLionProjects/PPP/main.cpp: In instantiation of ��std::ostream& operator<<(std::ostream&, const BTree<T, t>&) [with T = int; long unsigned int t = 2; std::ostream = std::basic_ostream<char>]��:
/mnt/c/Users/kim/CLionProjects/PPP/main.cpp:171:18: required from here
/mnt/c/Users/kim/CLionProjects/PPP/main.cpp:164:8: error: no match for ��operator<<�� (operand types are ��std::ostream�� {aka ��std::basic_ostream<char>��} and ��BTree<int, 2>::Node��)
164 | os << *(bt.root) << '\n';
| ~~~^~~~~~~~~~~~~
bt
is BTree<T, t>
, bt.root
is std::unique_ptr<BTree<T, t>::Node>
이므로 역 참조 연산자가와 일치해야한다고 생각 operator<<(std::ostream& os, const typename BTree<T, t>::Node& node)
하지만 내 컴파일러는 여전히 만족스럽지 않습니다.
어떻게 해결할 수 있습니까? 미리 감사드립니다.
답변
4 songyuanyao Aug 19 2020 at 20:33
operator<<
내부 클래스의 Node
경우 템플릿으로 정의되어 있지만 추론 되지 않은 컨텍스트 때문에 템플릿 매개 변수를 추론 할 수 없습니다 .
다음의 경우 P를 구성하는 데 사용되는 유형, 템플릿 및 유형이 아닌 값은 템플릿 인수 추론에 참여하지 않고 대신 다른 곳에서 추론되거나 명시 적으로 지정된 템플릿 인수를 사용 합니다. 템플릿 매개 변수가 추론되지 않은 컨텍스트에서만 사용되고 명시 적으로 지정되지 않은 경우 템플릿 인수 추론이 실패합니다.
- 중첩 이름 지정자 (범위 결정 연산자의 왼쪽에 모든
::
사용하여 지정된 유형의) 자격-ID를 :
비 템플릿으로 정의하고 클래스 정의에서 정의 할 수 있습니다. 예
template <typename T, std::size_t t>
class BTree {
...
class Node {
...
friend std::ostream& operator<< (std::ostream& os, const Node& node) {
if (node->leaf) {
for (std::size_t i = 0; i < node->getN() - 1; i++) {
os << node->key[i] << ' ';
}
os << node->key[node->getN() - 1];
} else {
for (std::size_t i = 0; i < node->getN(); i++) {
os << *node->child[i] << ' ' << node->key[i] << ' ';
}
os << *node->child[node->getN()];
}
return os;
}
...
};
...
};
frozenca Aug 19 2020 at 20:37
와, C ++ 템플릿은 너무 모호하고 멍청합니다.
작동 코드 :
#include <cassert>
#include <cstddef>
#include <iostream>
#include <memory>
#include <vector>
#include <utility>
template <typename T, std::size_t t>
class BTree {
static_assert(t >= 2);
class Node {
std::size_t n = 0;
public:
bool leaf = true;
std::vector<T> key;
std::vector<std::unique_ptr<Node>> child;
void setN(std::size_t N) {
n = N;
key.resize(n);
if (!leaf) {
child.resize(n + 1);
}
}
[[nodiscard]] std::size_t getN() const {
return n;
}
[[nodiscard]] bool isFull() const {
return n == 2 * t - 1;
}
friend std::ostream& operator<<(std::ostream& os, const BTree<T, t>::Node& node) {
if (node.leaf) {
for (std::size_t i = 0; i < node.getN() - 1; i++) {
os << node.key[i] << ' ';
}
os << node.key[node.getN() - 1];
} else {
for (std::size_t i = 0; i < node.getN(); i++) {
os << *node.child[i] << ' ' << node.key[i] << ' ';
}
os << *node.child[node.getN()];
}
return os;
}
};
std::unique_ptr<Node> root;
std::pair<const Node*, std::size_t> Search(const Node* x, const T& k) const {
std::size_t i = 0;
while (i < x->getN() && k > x->key[i]) {
i++;
}
if (i < x->getN() && k == x->key[i]) {
return {x, i};
} else if (x->leaf) {
return {nullptr, 0};
} else {
return Search(x->child[i].get(), k);
}
}
void SplitChild(Node* x, std::size_t i) {
if (!x) {
return;
}
auto y = x->child[i].get();
if (!y) {
return;
}
assert(!x->isFull() && y->isFull());
auto z = std::make_unique<Node>();
z->leaf = y->leaf;
z->setN(t - 1);
for (std::size_t j = 0; j < t - 1; j++) {
z->key[j] = y->key[j + t];
}
if (!y->leaf) {
for (std::size_t j = 0; j < t; j++) {
z->child[j] = std::move(y->child[j + t]);
}
}
x->setN(x->getN() + 1);
for (std::size_t j = x->getN(); j >= i && j < x->getN(); j--) {
x->child[j + 1] = std::move(x->child[j]);
}
x->child[i + 1] = std::move(z);
for (std::size_t j = x->getN(); j >= i && j < x->getN(); j--) {
x->key[j] = x->key[j - 1];
}
x->key[i] = y->key[t - 1];
y->setN(t - 1);
}
void InsertNonFull(Node* x, const T& k) {
std::size_t i = x->getN();
if (x->leaf) {
x->setN(i + 1);
while (i - 1 < x->getN() && k < x->key[i - 1]) {
x->key[i] = x->key[i - 1];
i--;
}
x->key[i] = k;
} else {
while (i - 1 < x->getN() && k < x->key[i - 1]) {
i--;
}
if (x->child[i]->isFull()) {
SplitChild(x, i);
if (k > x->key[i]) {
i++;
}
}
InsertNonFull(x->child[i].get(), k);
}
}
public:
BTree() {
root = std::make_unique<Node>();
}
[[nodiscard]] std::pair<const Node*, std::size_t> Search(const T& k) const {
return Search(root.get(), k);
}
void Insert(const T& k) {
if (root->isFull()) {
auto s = std::make_unique<Node>();
s->leaf = false;
s->setN(0);
s->child[0] = std::move(root);
root = std::move(s);
SplitChild(root.get(), 0);
InsertNonFull(root.get(), k);
} else {
InsertNonFull(root.get(), k);
}
}
friend std::ostream& operator<< (std::ostream& os, const BTree<T, t>& bt) {
return os << *(bt.root) << '\n';
}
};
int main() {
BTree<int, 2> tree;
tree.Insert(1);
tree.Insert(2);
tree.Insert(3);
tree.Insert(4);
tree.Insert(5);
tree.Insert(6);
tree.Insert(7);
tree.Insert(8);
tree.Insert(9);
tree.Insert(10);
std::cout << tree;
}