未定义对操作符的引用< [英] undefined reference to operator<<

查看:143
本文介绍了未定义对操作符的引用<的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个普通类(不是模板,也就是)与私人朋友运算符<



它的声明是:

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

它正在编译,然后链接到使用它的main函数,我使用它我得到一个未定义的引用...



然而,当我添加定义到主cpp文件的顶部,并删除friend声明,它工作正常。 ..



我如何在我的主要功能中使用它

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

不再有...



heres the linker error


/home/luke/Desktop/pathfinder/parse_world.cpp:34:未定义引用`pathfinder :: operator< ;<(std :: ostream& amp; pathfinder :: Position const&)'


/ p>

  #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 *> >世界;
typedef std :: vector< Node *>世界
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:
位置(const point_type& xPoint = 0,const point_type& yPoint = 0);
Position(const Position& position);
位置(位置&&位置);
〜Position();

位置& operator =(const 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_;
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();

节点& 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

现在删除好友声明后, :


无法将'std :: ostream {aka std :: basic_ostream}'值赋值给'std :: basic_ostream& / p>

它与std :: cout语句位于同一行...


$ b $

解决方案

我的猜想,从描述是你宣布两个运算符<< 但只定义一个。例如:

 命名空间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 ::可以通过ADL在类型 B 上找到的运算符函数,但是[2]声明并定义: :operator<< 。当编译器看到代码时:

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

它使用ADL并找到 A :: operator<< (从朋友声明)并使用它,但该函数是未定义的。如果删除 friend 声明,则在全局命名空间中声明和定义 operator 的单个实例



另外请注意,如果在程序中使用指令,这可能更难以发现,因为[2]中的定义可能没有显式地为参数命名 A 命名空间。这也将解释您可以定义类型的其余成员:

  // cpp [假设B的定义包含一个成员f 
使用命名空间A;
void B :: f(){
}



B :: f 驻留在全局命名空间中(在代码中),但由于使用了using指令,将会找到 B A 命名空间中,类型说明符将等效于 A :: B 解析 B 后,c $ c> void :: A :: B :: f(){}
。这将对自由功能发生



我建议您避免使用指令,因为它们允许像这样的微妙错误。另外请注意,您可以明确地在命名空间中定义运算符(但您还需要在命名空间中声明

 命名空间A {
struct B {friend std :: ostream& operator<<(std :: ostream& B const&);};
std :: ostream& operator<<<(std :: ostream& B const&);
}
std :: ostream& A :: operator< ostream& o,B const&){
return o;
}

这个技巧(通过完全限定来定义自然命名空间之外的自由函数)有时用来避免隐式声明它的函数的定义,这很容易出现这种类型的错误。例如,如果你在正确的命名空间,但签名略有不同:

 命名空间A {
struct B {
friend std: :ostream& operator<<<(std :: ostream& B const&); // [1]
};
std :: ostream& operator<<<(std :: ostream& b;&){// [3]
return o;
}
}

[3]中的定义也是一个声明,但是它声明了一个与[1]中声明的函数不同的函数,你可能最终会抓住你的头,问为什么链接器没有找到[1]。


I have a regular class (not a template, that is) with a private friend operator<<

it's declaration is:

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

in the cpp file it's definition is:

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

it is being compiled then linked to the main function which uses it, however when I use it I get an undefined reference...

however when I add the definition to the top of the main cpp file and remove the friend declaration, it works fine...

heres how I am using it in my main function

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

no more no less...

heres the linker error

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

and heres the class header...

#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

now after removing the friend declaration I am getting error messages like:

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

it is occuring on the same line as the std::cout statement...

So, whats the deal...

thanks in advance

解决方案

My guess, from the description is that you are declaring two operator<< but only defining one. For example:

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

The line [1] declares one A::operator<< function that can be found through ADL on the type B, but [2] declares and defines ::operator<<. When the compiler sees the code:

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

It use ADL and find A::operator<< (from the friend declaration) and use it, but that function is undefined. If you remove the friend declaration, there is a single instance of operator<< declared and defined in the global namespace and that will be found by regular lookup.

Also note that this can be harder to spot if there are using directives in your program, as the definition in [2] might not explicitly name the A namespace for the argument. This would also explain that you can define the rest of the members of the type:

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

The definition of B::f resides (in code) in the global namespace, but because of the using directive, B will be found in the A namespace and the type specifier will be equivalent to A::B what makes the definition equivalent to void ::A::B::f() {} after resolving B. This will not happen for free functions.

I would recommend that you avoid using directives as they allow for subtle errors like this one. Also note that you can actually define the operator in the namespace explicitly (but you will need to also declare it in the namespace:

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

This trick (defining free functions outside of their natural namespace by fully qualifying) is sometimes use to avoid the definition of the function implicitly declaring it, which is prone to this type of errors. For example, if you defined the operator in the proper namespace, but the signature was slightly different:

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

The definition in [3] is also a declaration, but it declares a function different than the one declared in [1], and you might end up scratching your head asking why the linker is not finding [1].

这篇关于未定义对操作符的引用&lt;的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆