2012-05-23 8 views
10

У меня есть регулярный класс (не шаблон, то есть) с собственным другом оператором < <неопределенная ссылка на оператор <<

это декларация является:

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

в CPP файла это определение является:

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

он компилируется затем присоединяют к основной функции, которая использует его, однако, когда я использую его я получаю неопределенную ссылку ...

однако, когда я добавить определение к верхней части основного файла CPP и удалить объявление друга, он отлично работает ...

вот как я использую его в своей основной функции

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

не больше не меньше ...

Heres ошибка линкера

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

и Херес Заголовок класса ...

#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 

теперь после удаления друга декларации я получаю сообщение об ошибке, как:

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

это встречающийся на той же строке, что и оператор станд :: соиЬ ...

Так, Что сделка ...

заранее спасибо

+0

Можете ли вы опубликовать, как вы называете это основной функцией? – MrWuf

+2

Кажется, что ваш файл cpp не правильно связывается. Что-то еще там работает? – chris

+0

Да, все остальное работает, как конструкторы и деструкторы –

ответ

13

Моя догадка, сюда m описание состоит в том, что вы объявляете два operator<<, но только определяете их. Например:

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; 
} 

Линия [1] объявляет одну A::operator<< функцию, которая может быть найдена через ADL от типа B, но [2] объявляющий и определяет ::operator<<. Когда компилятор видит код:

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

Он использует ADL и найти A::operator<< (от друга декларации) и использовать его, но эта функция не определена. Если вы удаляете объявление friend, существует один экземпляр operator<<, объявленный и определенный в глобальном пространстве имен, и который будет найден путем регулярного поиска.

Также обратите внимание, что это может быть труднее обнаружить, если в вашей программе есть директивы, так как определение в [2] может явно не указывать пространство имен A для аргумента.Это также объясняет, что вы можете определить остальные члены типа:

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

Определение B::f пребывает (в коде) в глобальном пространстве имен, но из-за использованием директивы, B будет найденный в пространстве имен A, и спецификатор типа будет эквивалентен A::B, что делает определение эквивалентным void ::A::B::f() {} после разрешения B. Это будет не Случаев для бесплатных функций.

Я бы рекомендовал вам избегать использования директив, поскольку они допускают такие тонкие ошибки, как этот. Также обратите внимание, что вы можете определить оператора в пространстве имен явно (но вам нужно будет также объявить его в пространстве имен:

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; 
} 

Этот прием (определение свободных функций за пределами их естественного пространства имен, полностью квалификацию) иногда используется, чтобы избежать определения функции, неявно объявляющей ее, которая подвержена этому типу ошибок. Например, если вы определили оператор в собственном пространстве имен, но подпись была несколько иной:

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

Определение в [3] также является объявлением, но оно объявляет функцию, отличную от той, которая была заявлена ​​в [1], и вы можете почесать голову, спрашивая, почему компоновщик не находит [1].

+0

Я избавился от объявления друга и теперь получаю ошибки, такие как ошибка: не может связывать 'std :: ostream {aka std :: basic_ostream }' lvalue to 'std :: basic_ostream &&' –

+0

@LukeSanAntonio, можете ли вы разместить те и какие строки они возникают? – chris

+0

обязательно ознакомьтесь с обновленным вопросом –

0

Давид дал очень хороший ответ на вопрос. Здесь я просто предоставляю пример для легкого понимания.

в моем файле заголовка:

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

В файле 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; 
} 

выше даст вам неопределенную ссылку на оператора < < (.., Const SomeBamClass &) при попытке для связи с этой библиотекой из ваших собственных приложений, потому что это объявление и реализация оператора вне пространства имен.

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

Единственное, работает для меня, чтобы добавить пространство имен ограды функции друга в файле реализации:

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

используя ... BamTools :: оператор < < (..., Const BamTools :: SomeBamClass &) приведет к ошибке компилятора для моего g ++ 5.4.0.

Смежные вопросы