[解決済み] operator<< への未定義の参照
質問
通常のクラス(テンプレートではありません)に、プライベートフレンドオペレータ<<.があります。
という宣言があります。
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 ファイルの先頭に追加し、フレンド宣言を削除すると、正常に動作するようになりました...
私のメイン関数でどのようにそれを使用しているかは、次のとおりです。
std::cout << node->getPosition() << std::endl;
これ以上でも以下でもない...
リンカーエラーが表示されます。
<ブロッククオート/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
friend宣言を削除したら、次のようなエラーメッセージが表示されるようになりました。
std::ostream {aka std::basic_ostream}' lvalue を 'std::basic_ostream&&' にバインドできない。
std::coutステートメントと同じ行で発生しています...
さて、どうしたものか...。
よろしくお願いします
どのように解決するのですか?
記述から推測すると、2つの
operator<<
が、1つだけ定義されています。例えば
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]の行では、1つの
A::operator<<
という型にADLを通して見つけることができる関数です。
B
が、[2]では
::operator<<
. コンパイラがこのコードを見たとき
A::B b;
std::cout << b;
ADLを使用し
A::operator<<
(friend宣言から)それを使うが、その関数は未定義である。もし
friend
宣言のインスタンスが1つだけ存在します。
operator<<
グローバル名前空間で宣言され、定義されたものは、通常のルックアップで見つかります。
また、プログラム中に using ディレクティブがある場合、[2] の定義が明示的に
A
の名前空間が引数になります。これは、次のような説明にもなります。
定義
は、その型の残りのメンバーである。
// cpp [assume that the definition of B contained a member f
using namespace A;
void B::f() {
}
の定義は
B::f
は (コード上) グローバルな名前空間に存在しますが、using ディレクティブがあるためです。
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]を見つけられないのはなぜかと頭を悩ませることになるかもしれません。
関連
-
[解決済み】C++エラーです。"配列は中括弧で囲まれたイニシャライザーで初期化する必要がある"
-
[解決済み】「std::operator」で「operator<<」にマッチするものがない。
-
[解決済み】デバッグアサーションに失敗しました
-
[解決済み] とは何ですか! (not not)演算子とは何ですか?
-
[解決済み] C言語では「?」演算子は何をするのですか?
-
[解決済み] JavaScriptに「NULL合体」演算子はありますか?
-
[解決済み】C/C++の"-->"演算子とは何ですか?
-
[解決済み】JavaScriptの比較では、どちらの等号演算子(== vs ===)を使うべきですか?
-
[解決済み】Pythonに三項条件演算子はありますか?
-
[解決済み] リファレンス - このシンボルはPHPで何を意味するのですか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】C++でint型に無限大を設定する
-
[解決済み】非静的メンバ関数への参照を呼び出す必要がある
-
[解決済み】Visual Studio 2015で「非標準の構文。'&'を使用してメンバーへのポインターを作成します」エラー
-
[解決済み】C++ 式はポインタからオブジェクトへの型を持っている必要があります。
-
[解決済み】関数名の前に期待されるイニシャライザー
-
[解決済み】テンプレートの引数1が無効です(Code::Blocks Win Vista) - テンプレートは使いません。
-
[解決済み】C++の変数はイニシャライザーを持っているが、不完全な型?
-
[解決済み】cc1plus:エラー:g++で認識されないコマンドラインオプション"-std=c++11"
-
[解決済み】浮動小数点数の乱数生成
-
[解決済み] gdbを使用してもデバッグシンボルが見つからない