2014-11-25 3 views
1

이 질문은 여기에 상세한 답변을 가지고에 과부하 : 나는 중첩 된 서브 클래스를 오버로드하려고 Overloading operator<<: cannot bind lvalue to ‘std::basic_ostream<char>&&’C++ : 연산자 << 중첩 된 클래스

을하고 operator<< 과부하하려고 시간을 보냈다. 조금만 연구했지만 아직 해결할 수 없었습니다. 어떤 도움이 필요합니까?

Undefined symbols for architecture x86_64: 
    "operator<<(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, LinkedBinaryTree<int>::Position const&)", referenced from: 
     std::__1::basic_ostream<char, std::__1::char_traits<char> >& operator<<<int>(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, LinkedBinaryTree<int> const&) in p_7_1-9fc2c2.o 
ld: symbol(s) not found for architecture x86_64 
clang: error: linker command failed with exit code 1 (use -v to see invocation) 

p_7_1.cpp :

#include "tree.hpp" 

typedef LinkedBinaryTree<int> Tree; 


#include <iostream> 

using namespace std; 


int main() { 
    // Test if tree works: 
    Tree lbt; 
    cout << lbt.empty() << endl; 
    lbt.addRoot(); 
    lbt.addRoot(); 
    cout << lbt.empty() << endl; 
    cout << lbt.size() << endl; 
    lbt.expandExternal(lbt.root()); 
    cout << lbt.empty() << endl; 
    cout << lbt.size() << endl; 

    *(lbt.root()) = 12; 
    cout << lbt; 
} 

tree.hpp :

#ifndef LINKED_BINARY_TREE_HPP 
#define LINKED_BINARY_TREE_HPP 

#include <list> 

template <typename T> class LinkedBinaryTree; 
template <typename T> std::ostream& operator<<(std::ostream& os, const LinkedBinaryTree<T>& lbt); 
template <typename T> std::ostream& operator<<(std::ostream& os, const typename LinkedBinaryTree<T>::Position& p); 

template <typename T> 
class LinkedBinaryTree { 
protected: 
    struct Node {   // a node of the tree 
    T elt;  // element value 
    Node* par;  // parent 
    Node* left;  // left child 
    Node* right;  // right child 
    Node() : elt(), par(NULL), left(NULL), right(NULL) { } // constructor 
    }; 

public: 
    class Position {  // position in the tree 
    private:   // 
    Node* v;   // pointer to the node 
    public: 
    Position(Node* _v = NULL) : v(_v) { } // constructor 
    T& operator*()   // get element 
    { return v->elt; }   // 
    Position left() const   // get left child 
    { return Position(v->left); }  // 
    Position right() const  // get right child 
    { return Position(v->right); } // 
    Position parent() const  // get parent 
    { return Position(v->par); }  // 
    bool isRoot() const   // root of the tree? 
    { return v->par == NULL; }  // 
    bool isExternal() const  // an external node? 
    { return v->left == NULL && v->right == NULL; } // 
    friend class LinkedBinaryTree; // give tree access 
    public: 
    friend std::ostream& operator<<(std::ostream& os, const typename LinkedBinaryTree<T>::Position& p); 
    friend std::ostream& operator<< <T>(std::ostream& os, const LinkedBinaryTree<T>& lbt); 
    }; 
    typedef std::list<Position> PositionList; // list of positions 
public:      // 
    LinkedBinaryTree();    // constructor 
    int size() const;    // number of nodes 
    bool empty() const;    // is tree empty? 
    Position root() const;   // get the root 
    PositionList positions() const;  // list of nodes 
    void addRoot();    // add root to empty tree 
    void expandExternal(const Position& p); // expand external node 
    Position removeAboveExternal(const Position& p); // remove p and parent 
       // housekeeping functions omitted... 
protected:   // local utilities 
    void preorder(Node* v, PositionList& pl) const; // preorder utility 
public: 
    friend std::ostream& operator<< <T>(std::ostream& os, const LinkedBinaryTree<T>& lbt); 
private:      // 
    Node* _root;   // pointer to the root 
    int n;   // number of nodes 
};    // 

template <typename T> 
LinkedBinaryTree<T>::LinkedBinaryTree() // constructor 
    : _root(NULL), n(0) { } 

template <typename T> 
int LinkedBinaryTree<T>::size() const // number of nodes 
{ return n; } 

template <typename T> 
bool LinkedBinaryTree<T>::empty() const // is tree empty? 
{ return size() == 0; } 

template <typename T> 
typename LinkedBinaryTree<T>::Position LinkedBinaryTree<T>::root() const // get the root 
{ return Position(_root); } 

template <typename T> 
typename LinkedBinaryTree<T>::PositionList LinkedBinaryTree<T>::positions() const { 
    PositionList pl; 
    preorder(_root, pl);  // preorder traversal 
    return PositionList(pl); // return resulting list 
} 

template <typename T> 
void LinkedBinaryTree<T>::addRoot() // add root to empty tree 
{ _root = new Node; n = 1; } 

template <typename T> 
void LinkedBinaryTree<T>::expandExternal(const Position& p) { 
    Node* v = p.v;  // p's node 
    v->left = new Node;  // add a new left child 
    v->left->par = v;  // v is its parent 
    v->right = new Node;  // and a new right child 
    v->right->par = v;  // v is its parent 
    n += 2;   // two more nodes 
} 

template <typename T> 
typename LinkedBinaryTree<T>::Position // remove p and parent 
LinkedBinaryTree<T>::removeAboveExternal(const Position& p) { 
    Node* w = p.v; Node* v = w->par; // get p's node and parent 
    Node* sib = (w == v->left ? v->right : v->left); 
    if (v == _root) {  // child of root? 
    _root = sib;  // ...make sibling root 
    sib->par = NULL; 
    } 
    else { 
    Node* gpar = v->par;   // w's grandparent 
    if (v == gpar->left) gpar->left = sib; // replace parent by sib 
    else gpar->right = sib; 
    sib->par = gpar; 
    } 
    delete w; delete v;  // delete removed nodes 
    n -= 2;   // two fewer nodes 
    return Position(sib); 
} 

// preorder traversal 
template <typename T> 
void LinkedBinaryTree<T>::preorder(Node* v, PositionList& pl) const { 
    pl.push_back(Position(v)); // add this node 
    if (v->left != NULL)  // traverse left subtree 
    preorder(v->left, pl); 
    if (v->right != NULL)  // traverse right subtree 
    preorder(v->right, pl); 
} 

template <typename T> 
std::ostream& operator<<(std::ostream& os, const LinkedBinaryTree<T>& lbt){ 
    os << lbt.root(); 
    // os << *(lbt.root()); 
    return os; 
} 

template <typename T> 
std::ostream& operator<<(std::ostream& os, const typename LinkedBinaryTree<T>::Position& p) { 
    os << *p;   // Other func stuff will be here later 
    return os; 
} 

#endif 

UPDATE :

내가 g++ -std=c++11 -lm -ggdb -g -O0 -Wall p_7_1.cpp -o p_7_1를 사용하여 컴파일하려고 할 때마다, 그것은 나에게 오류를 제공 : 연산자 오버로드에 대해 explanation by david-rodríguez-dribeas이 있습니다. 중첩 된 클래스 그는 operator<<을 인라인으로 신고하는 것이 좋습니다.

+0

나는 클래스 내 친구 연산자를 선언하는 경우 내가 일을 얻을 수 있습니다 :'''클래스 A {클래스 B를 { 친구 std :: ostream & 연산자 << (...) {...}}; };'''. 클래스의 정의를 가져 가면 여전히 작동하지 않습니다. – RafazZ

+0

-Wall로 컴파일하고 실제로 경고를 읽습니다. –

+0

[C++ 템플릿 친구 연산자 과부하] 가능한 복제본 (http://stackoverflow.com/questions/3989678/c) -template-friend-operator-overloading) –

답변

1

하루 종일 읽은 후 해결책을 찾은 것 같아요. 나는 here에서 조언을 받아 선언문을 인라인에 넣었습니다. 그 외에도 GCC를 4.9로 업데이트 (이전 4.2.1을 사용)하고 WHOOAAAhhh - 그들은 동작 방식을 약간 변경했습니다. 어쨌든 중첩 된 클래스에 대한 최상의 솔루션은 인라인 정의 인 것처럼 보입니다. 고정 코드는 다음과 같습니다.

p_7_1.cpp :

#include "tree.hpp" 

typedef LinkedBinaryTree<int> Tree; 

#include <iostream> 

using namespace std; 

int main() { 
    // Test if tree works: 
    Tree lbt; 
    cout << lbt.empty() << endl; 
    lbt.addRoot(); 
    lbt.addRoot(); 
    cout << lbt.empty() << endl; 
    cout << lbt.size() << endl; 
    lbt.expandExternal(lbt.root()); 
    cout << lbt.empty() << endl; 
    cout << lbt.size() << endl; 

    // rotateLeft(lbt.root().right()); 
    *(lbt.root()) = 12; 
    *(lbt.root().left()) = 11; 
    *(lbt.root().right()) = 13; 
    cout << lbt; 
} 

tree.hpp :

#ifndef LINKED_BINARY_TREE_HPP 
#define LINKED_BINARY_TREE_HPP 

#include <cstdlib> 
#include <iostream> 
#include <list> 

template <typename T> class LinkedBinaryTree; 
template <typename T> std::ostream& operator<<(std::ostream& os, const LinkedBinaryTree<T>& lbt); 
template <typename T> std::ostream& operator<<(std::ostream& os, const typename LinkedBinaryTree<T>::Position& p); 

template <typename T> 
class LinkedBinaryTree { 
protected: 
    struct Node {   // a node of the tree 
    T elt;  // element value 
    Node* par;  // parent 
    Node* left;  // left child 
    Node* right;  // right child 
    Node() : elt(), par(NULL), left(NULL), right(NULL) { } // constructor 
    }; 

public: 
    class Position {  // position in the tree 
    private:   // 
    Node* v;   // pointer to the node 
    public: 
    Position(Node* _v = NULL) : v(_v) { } // constructor 
    T& operator*()   // get element 
    { return v->elt; }   // 
    Position left() const   // get left child 
    { return Position(v->left); }  // 
    Position right() const  // get right child 
    { return Position(v->right); } // 
    Position parent() const  // get parent 
    { return Position(v->par); }  // 
    bool isRoot() const   // root of the tree? 
    { return v->par == NULL; }  // 
    bool isExternal() const  // an external node? 
    { return v->left == NULL && v->right == NULL; } // 
    friend class LinkedBinaryTree; // give tree access 
    public: 
    //friend std::ostream& operator<< <T> (std::ostream& os, const LinkedBinaryTree<T>::Position& p); 
    friend inline std::ostream& operator<<(std::ostream& os, const Position& p) { 
     os << '['; 
     if (!p.isExternal()){ 
    os << p.left(); 
     } 
     os << ' '; 
     os << *(Position(p)); 
     os << ' '; 
     if (!p.isExternal()) { 
    os << p.right(); 
     } 
     os << ']'; 

     return os; 
    } 

    friend std::ostream& operator<< <T>(std::ostream& os, const LinkedBinaryTree<T>& lbt); 
    }; 
    typedef std::list<Position> PositionList; // list of positions 
public:      // 
    LinkedBinaryTree();    // constructor 
    int size() const;    // number of nodes 
    bool empty() const;    // is tree empty? 
    Position root() const;   // get the root 
    PositionList positions() const;  // list of nodes 
    void addRoot();    // add root to empty tree 
    void expandExternal(const Position& p); // expand external node 
    Position removeAboveExternal(const Position& p); // remove p and parent 
       // housekeeping functions omitted... 
protected:   // local utilities 
    void preorder(Node* v, PositionList& pl) const; // preorder utility 
public: 
    friend std::ostream& operator<< <T>(std::ostream& os, const LinkedBinaryTree<T>& lbt); 
private:      // 
    Node* _root;   // pointer to the root 
    int n;   // number of nodes 
};    // 

template <typename T> 
LinkedBinaryTree<T>::LinkedBinaryTree() // constructor 
    : _root(NULL), n(0) { } 

template <typename T> 
int LinkedBinaryTree<T>::size() const // number of nodes 
{ return n; } 

template <typename T> 
bool LinkedBinaryTree<T>::empty() const // is tree empty? 
{ return size() == 0; } 

template <typename T> 
typename LinkedBinaryTree<T>::Position LinkedBinaryTree<T>::root() const // get the root 
{ return Position(_root); } 

template <typename T> 
typename LinkedBinaryTree<T>::PositionList LinkedBinaryTree<T>::positions() const { 
    PositionList pl; 
    preorder(_root, pl);  // preorder traversal 
    return PositionList(pl); // return resulting list 
} 

template <typename T> 
void LinkedBinaryTree<T>::addRoot() // add root to empty tree 
{ _root = new Node; n = 1; } 

template <typename T> 
void LinkedBinaryTree<T>::expandExternal(const Position& p) { 
    Node* v = p.v;  // p's node 
    v->left = new Node;  // add a new left child 
    v->left->par = v;  // v is its parent 
    v->right = new Node;  // and a new right child 
    v->right->par = v;  // v is its parent 
    n += 2;   // two more nodes 
} 

template <typename T> 
typename LinkedBinaryTree<T>::Position // remove p and parent 
LinkedBinaryTree<T>::removeAboveExternal(const Position& p) { 
    Node* w = p.v; Node* v = w->par; // get p's node and parent 
    Node* sib = (w == v->left ? v->right : v->left); 
    if (v == _root) {  // child of root? 
    _root = sib;  // ...make sibling root 
    sib->par = NULL; 
    } 
    else { 
    Node* gpar = v->par;   // w's grandparent 
    if (v == gpar->left) gpar->left = sib; // replace parent by sib 
    else gpar->right = sib; 
    sib->par = gpar; 
    } 
    delete w; delete v;  // delete removed nodes 
    n -= 2;   // two fewer nodes 
    return Position(sib); 
} 

// preorder traversal 
template <typename T> 
void LinkedBinaryTree<T>::preorder(Node* v, PositionList& pl) const { 
    pl.push_back(Position(v)); // add this node 
    if (v->left != NULL)  // traverse left subtree 
    preorder(v->left, pl); 
    if (v->right != NULL)  // traverse right subtree 
    preorder(v->right, pl); 
} 

template <typename T> 
std::ostream& operator<<(std::ostream& os, const LinkedBinaryTree<T>& lbt){ 
    os << lbt.root(); 
    os << std::endl; 
    // os << *(lbt.root()); 
    return os; 
} 

/* 
template <typename T> 
std::ostream& operator<<(std::ostream& os, const typename LinkedBinaryTree<T>::Position& p) { 
    os << '['; 
    if (!p.isExternal()){ 
    os << p.left(); 
    } 
    os << ' '; 
    os << *(Position(p)); 
    os << ' '; 
    if (!p.isExternal()) { 
    os << p.right(); 
    } 
    os << ']'; 

    return os; 
} 
*/ 
#endif 
+0

이 선언은'std :: ostream & os, std :: ostream & os, const typename LinkedBinaryTree :: Position & p);'템플릿이 결코 사용되지 않는다는 것을 의미하며, 추론 할 수없는 상황 * 때문에 오히려 쓸모 없다. –

+0

오, 나는 그것을 std :: ostream & operator << (std :: ostream & os, const LinkedBinaryTree & lbt)에서 사용하기 때문에 선언해야한다고 생각했다. {' – RafazZ

+0

이 선언을 사용하고 있지 않습니다. 과부하 해결에서 절대로 선택되지 않습니다. 인라인 연산자''를 제거하고 컴파일러 오류가 아닌 컴파일러를 확인하십시오. –