2012-05-23 36 views
10

Tôi có một lớp thông thường (không phải là một mẫu, có nghĩa là) với một nhà điều hành người bạn tin < <tài liệu tham khảo không xác định để điều hành <<

nó tuyên bố là:

std::ostream& operator<<(std::ostream& out, const Position& position); 

trong cpp nộp đó là định nghĩa là:

std::ostream& operator<<(std::ostream& out, const Position& position) 
{ 
    out << position.getXPoint() << "," << position.getYPoint(); 
    return out; 
} 

nó đang được biên dịch rồi liên kết với chức năng chính sử dụng nó, tuy nhiên khi tôi sử dụng nó, tôi nhận được tham chiếu không xác định ...

tuy nhiên khi tôi thêm các định nghĩa để phía trên cùng của tập tin cpp chính và loại bỏ các tuyên bố người bạn, nó hoạt động tốt ...

heres làm thế nào tôi đang sử dụng nó trong chức năng chính của tôi

std::cout << node->getPosition() << std::endl; 

không hơn không kém ...

heres lỗi mối liên kết

/home/luke/Desktop/pathfinder/parse_world.cpp:34: undefined reference to `pathfinder::operator<<(std::ostream&, pathfinder::Position const&)'

và heres lớp tiêu đề ...

#ifndef PATHFINDER_H 
#define PATHFINDER_H 
#include <ostream> 
#include <istream> 
#include <list> 
#include <vector> 
#include <stdexcept> 
#include <cstring> 
namespace pathfinder 
{ 
class Node; 
typedef unsigned int GCost; 
typedef std::vector<std::vector<Node*> > World; 
typedef std::vector<Node*> WorldRow; 
class Position 
{ 
public: 
    typedef unsigned int point_type; 
private: 
    point_type* xPoint_; 
    point_type* yPoint_; 
    friend std::ostream& operator<<(std::ostream& out, const Position& position); 
public: 
    Position(const point_type& xPoint = 0, const point_type& yPoint = 0); 
    Position(const Position& position); 
    Position(Position&& position); 
    ~Position(); 

    Position& operator=(const Position& position); 
    Position& operator=(Position&& position); 

    point_type getXPoint() const; 
    point_type getYPoint() const; 

    void setXPoint(const point_type& xPoint); 
    void setYPoint(const point_type& yPoint); 
}; 
class Node 
{ 
private: 
    bool* isPassable_; 
    bool* isStartingNode_; 
    bool* isTargetNode_; 
    Position* position_; 
    GCost* additionalGCost_; 
    Node* parent_; 
public: 
    Node(const bool& isPassable = true, const bool& isStartingNode = false, const bool& isTargetNode = false, const Position& position = Position(0,0), const GCost& additionalGCost = 0, Node* parent = nullptr); 
    Node(const Node& node); 
    Node(Node&& node); 
    ~Node(); 

    Node& operator=(const Node& node); 
    Node& operator=(Node&& node); 

    bool isPassable() const; 
    bool isStartingNode() const; 
    bool isTargetNode() const; 
    Position getPosition() const; 
    GCost getAdditionalGCost() const; 
    Node* getParent() const; 

    void setAsPassable(const bool& isPassable); 
    void setAsStartingNode(const bool& isStartingNode); 
    void setAsTargetNode(const bool& isTargetNode); 
    void setPosition(const Position& position); 
    void setAdditionalGCost(const GCost& additionalGCost); 
    void setParent(Node* parent); 
}; 
class WorldHelper 
{ 
public: 
    static World fromStream(std::istream& input); 
    static void syncPositions(World& world); 
    static void uninitializeWorld(World& world); 
    static Node* findStartingNode(const World& world); 
    static Node* findTargetNode(const World& world); 
}; 
class Pathfinder 
{ 
public: 
    virtual std::list<Node*> operator()(World& world) const = 0; 
}; 
}; 
#endif //PATHFINDER_H 

bây giờ sau khi loại bỏ các tuyên bố người bạn Tôi nhận được thông báo lỗi như:

cannot bind ‘std::ostream {aka std::basic_ostream}’ lvalue to ‘std::basic_ostream&&’

nó được xảy ra trên cùng một dòng như tuyên bố std :: cout ...

Vì vậy, whats thỏa thuận ...

cảm ơn trước

+0

Bạn có thể đăng cách bạn đang gọi nó trong chức năng chính không? – MrWuf

+2

Có vẻ như tệp cpp của bạn không liên kết đúng cách. Có gì khác trong đó làm việc? – chris

+0

Có, mọi thứ khác hoạt động, như các nhà xây dựng và các nhà hủy diệt –

Trả lời

13

tôi đoán, fro m mô tả là bạn đang khai báo hai số operator<< nhưng chỉ xác định một. Ví dụ:

namespace A { 
    struct B { 
     friend std::ostream& operator<<(std::ostream&, B const &); // [1] 
    }; 
} 
std::ostream& operator<<(std::ostream& o, A::B const &) {  // [2] 
    return o; 
} 

Dòng [1] tuyên bố một A::operator<< chức năng có thể được tìm thấy thông qua ADL vào loại B, nhưng [2] tuyên bố và xác định ::operator<<. Khi trình biên dịch thấy mã:

A::B b; 
std::cout << b; 

Nó sử dụng ADL và tìm A::operator<< (từ việc kê khai bạn bè) và sử dụng nó, nhưng chức năng đó là không xác định. Nếu bạn xóa tuyên bố friend, có một trường hợp duy nhất là operator<< được khai báo và xác định trong không gian tên chung và sẽ được tìm thấy bằng tra cứu thông thường. Cũng xin lưu ý rằng điều này có thể khó phát hiện hơn nếu có sử dụng chỉ thị trong chương trình của bạn, vì định nghĩa trong [2] có thể không nêu rõ tên không gian tên A cho đối số.Điều này cũng sẽ giải thích rằng bạn có thể xác định phần còn lại của các thành viên của các loại:

// cpp [assume that the definition of B contained a member f 
using namespace A; 
void B::f() { 
} 

Định nghĩa của B::f cư trú (trong code) trong không gian tên toàn cầu, nhưng vì chỉ sử dụng, B sẽ được tìm thấy trong không gian tên A và trình chỉ định loại sẽ tương đương với A::B điều gì làm cho định nghĩa tương đương với void ::A::B::f() {} sau khi giải quyết B. Điều này sẽ không xảy ra cho các chức năng miễn phí.

Tôi khuyên bạn nên tránh sử dụng các chỉ thị khi chúng cho phép các lỗi tinh vi như thế này. Cũng lưu ý rằng bạn thực sự có thể định nghĩa các nhà điều hành trong không gian tên một cách rõ ràng (nhưng bạn sẽ cần phải cũng tuyên bố nó trong không gian tên:

namespace A { 
    struct B { friend std::ostream& operator<<(std::ostream&, B const &); }; 
    std::ostream& operator<<(std::ostream&, B const &); 
} 
std::ostream& A::operator<<(std::ostream& o, B const &) { 
    return o; 
} 

lừa này (quy định chức năng miễn phí bên ngoài namespace tự nhiên của họ bằng cách hoàn toàn Ví dụ, nếu bạn định nghĩa toán tử trong không gian tên thích hợp, nhưng chữ ký hơi khác một chút:

namespace A { 
    struct B { 
     friend std::ostream& operator<<(std::ostream&, B const &); // [1] 
    }; 
    std::ostream& operator<<(std::ostream&, B &) {    // [3] 
     return o; 
    } 
} 

Định nghĩa trong [3] cũng là một khai báo, nhưng nó khai báo một hàm khác với hàm được khai báo trong [1], và bạn có thể sẽ gãi đầu hỏi tại sao mối liên kết không tìm thấy [1].

+0

Tôi đã loại bỏ tuyên bố kết bạn và bây giờ tôi nhận được lỗi như lỗi: không thể liên kết 'std :: ostream {aka std :: basic_ostream }' lvalue to 'std :: basic_ostream &&' –

+0

@LukeSanAntonio, bạn có thể đăng những dòng đó và chúng xuất hiện không? – chris

+0

hãy kiểm tra câu hỏi cập nhật –

0

David đã đưa ra một câu trả lời rất hay cho câu hỏi. Ở đây tôi chỉ cung cấp một ví dụ cho sự hiểu biết dễ dàng.

trong tập tin tiêu đề của tôi:

namespace BamTools { 
class SomeBamClass { 
..... 
public: 
    friend std::ostream& operator<<(std::ostream& ous, const SomeBamClass& ba); 
    ..... 
} 
} 

Trong tập tin cpp:

using namespace BamTools; // this work for Class member function but not friends 
using namespace std; 

........ 
std::ostream& operator<<(std::ostream &ous, const SomeBamClass &ba) { 
    // actual implementation 
    return ous; 
} 

trên sẽ cung cấp cho bạn tài liệu tham khảo không xác định để điều hành < < (.., const SomeBamClass &) khi bạn cố gắng để liên kết tới thư viện này từ các ứng dụng của riêng bạn bởi vì nó là khai báo và thực hiện toán tử bên ngoài vùng tên.

undefined reference to `BamTools::operator<<(std::ostream&, BamTools::SomeBamClass const&)' 

Điều duy nhất làm việc cho tôi là thêm namespace sự nhốt vào các hàm bạn bè trong file thực hiện:

namespace BamTools { 
std::ostream& operator<<(std::ostream &ous, const SomeBamClass &ba) { 
... 
    return ous; 
} 
} 

sử dụng ... BamTools :: operator < < (..., const BamTools :: SomeBamClass &) sẽ dẫn đến lỗi trình biên dịch cho g ++ 5.4.0 của tôi.

Các vấn đề liên quan