C++ 对运算符的未定义引用<<

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10712380/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 14:22:17  来源:igfitidea点击:

undefined reference to operator<<

c++operatorsoperator-overloading

提问by David Rodríguez - dribeas

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:

在cpp文件中它的定义是:

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...

但是,当我将定义添加到主 cpp 文件的顶部并删除朋友声明时,它工作正常......

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&)'

/home/luke/Desktop/pathfinder/parse_world.cpp:34:未定义对`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&&'

无法将“std::ostream {aka std::basic_ostream}”左值绑定到“std::basic_ostream&&”

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

它与 std::cout 语句发生在同一行...

So, whats the deal...

那么,有什么关系...

thanks in advance

提前致谢

回答by David Rodríguez - dribeas

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

我的猜测是,根据描述,您声明了两个,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;
}

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:

第 [1] 行声明了一个A::operator<<可以通过 ADL 在类型上找到的函数B,但 [2] 声明并定义了::operator<<。当编译器看到代码时:

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 frienddeclaration, there is a single instance of operator<<declared and defined in the global namespace and that will be found by regular lookup.

它使用 ADL 并查找A::operator<<(来自朋友声明)并使用它,但该函数未定义。如果删除friend声明,则operator<<在全局命名空间中有一个声明和定义的实例,并且可以通过常规查找找到。

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 Anamespace for the argument. This would also explain that you can definethe rest of the members of the type:

另请注意,如果您的程序中有 using 指令,这可能更难发现,因为 [2] 中的定义可能没有明确A命名参数的命名空间。这也说明您可以定义该类型的其余成员:

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

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

的定义B::f(在代码中)在全局命名空间中,但由于 using 指令,B将在A命名空间中找到并且类型说明符将等效于A::B使定义等效于void ::A::B::f() {}解析后的内容B。对于免费功能,这不会发生。

I would recommend that you avoid using directives as they allow for subtle errors like this one. Also note that you can actually definethe operator in the namespace explicitly (but you will need to also declareit 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].

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

回答by Kemin Zhou

David gave a very good answer to the question. Here I am just providing an example for easy understanding.

大卫很好地回答了这个问题。这里我只是举个例子,方便理解。

in my header file:

在我的头文件中:

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

In the cpp file:

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

The above will give you undefined reference to operator<<(.., const SomeBamClass&) when you try to link to this library from your own applications because it is declaration and implementation of an operator outside the namespace.

当您尝试从您自己的应用程序链接到该库时,上述内容将为您提供对 operator<<(.., const SomeBamClass&) 的未定义引用,因为它是命名空间之外的运算符的声明和实现。

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

The only thing works for me is to add namespace inclosure to the friend function in the implementation file:

唯一对我有用的是在实现文件中向友元函数添加命名空间封闭:

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

using ... BamTools::operator<<(..., const BamTools::SomeBamClass&) will result in a compiler error for my g++ 5.4.0.

使用 ... BamTools::operator<<(..., const BamTools::SomeBamClass&) 将导致我的 g++ 5.4.0 出现编译器错误。