2017-06-25 12 views
4

誰かがg ++からの警告を私に説明することができますか?名前空間内で宣言された友人演算子を定義する警告

私は(Visual Studioの(2017年のコミュニティ)から(おかげRobert.M)ない6.3.0(++グラムから)ではなく打ち鳴らすから++(3.8.1)と)を取得次のコード

#include <iostream> 

namespace foo 
{ 
    struct bar 
    { friend std::ostream & operator<< (std::ostream &, bar const &); }; 
} 

std::ostream & foo::operator<< (std::ostream & o, foo::bar const &) 
{ return o; } 

int main() 
{ 
    foo::bar fb; 

    std::cout << fb; 
} 

を考えますこの警告

tmp_002-11,14,gcc,clang.cpp:10:16: warning: ‘std::ostream& foo::operator<<(std::ostream&, const foo::bar&)’ has not been declared within foo 
std::ostream & foo::operator<< (std::ostream & o, foo::bar const &) 
       ^~~ 
tmp_002-11,14,gcc,clang.cpp:7:29: note: only here as a friend 
    { friend std::ostream & operator<< (std::ostream &, bar const &); }; 
          ^~~~~~~~ 

私は

私のイニシアと間違って何
namespace foo 
{ 
    std::ostream & operator<< (std::ostream & o, bar const &) 
    { return o; } 
} 

けど...を次のように私はオペレータを定義することができることを知っていますコード?

+1

これは役立つはずです https://stackoverflow.com/questions/3891402/operator-overloading-and-namespaces –

+0

解決策が見つかったのですか、それともなぜこのようなコメントがありましたか?また、なぜあなたは最初にそこに友人を置いたのですか?これは仕事に必要ですか? – Ilendir

+0

@Ilendir - 現時点では "解決策"が見つかりませんでした(しかし、私は "解決策"を探しません;私は説明を求めます)。 (オリジナルの、より複雑な)コードの最初のバージョンは私のものではなく、オープンソースコードからのものです。私は、2番目のブロック( 'namespace foo'ブロック内の演算子)で示された方法でコードを修正することを提案しましたが、私の疑問は残っています:なぜ最初は間違っていますか? Robert.Mからの答えは間違っています。 – max66

答えて

3

このsimpmeプログラムを考えてみましょう。

は今、このことを考慮してください。

namespace xxx {} 
void xxx::bar() {} 

これも同じecact理由で失敗しますが、barは、名前空間xxxで宣言されていません。

2つを組み合わせると、その組み合わせが突然法的になる理由はありません。 barはまだ名前空間xxxで宣言されていません。それでもclangはそれを許します。この動作は一貫性がなく、混乱し、バグとして最もよく説明されています。

0

私はビジュアルスタジオを使用していたので、問題が解決するかどうかはわかりませんが、私が間違って見つけたのはあなたのオペレータの宣言だけでした。 Basiclyそれは

常に

 const type_name variable_id &; 
あるアンパサンドは常に最後に来て、constが、それが今実行している私にとって、最初に来ます。

あなたのオペレータの宣言を変更してまでする必要がありますあなたの定義で

 friend std::ostream & operator<< (std::ostream &,const bar&); 

下:

std::ostream & foo::operator<< (std::ostream & o, const foo::bar &) 
+0

答えてくれてありがとうございます、あなたは間違っています:規則は、定数が宣言されていない部分の右側に 'const'が置かれていることです(例:' int const * '定数の整数'int * const'は変更可能な整数への定数ポインタを宣言します)、' const'の左側に何もない場合にのみ、右側の部分に適用されます( 'const int *'は変更可能です定数整数へのポインタ、 'int const *'とまったく同じです)。したがって、 'const bar&'は 'bar const&'とまったく同じものです。 – max66

+0

しかし...申し訳ありません...ビジュアルスタジオでは、警告、コードサンプルのコンパイル、またはノーを取得していますか? – max66

+0

はい、0のエラー、0の警告、私は、同じことがオペレータの定義においてより低く行われなければならないということを忘れていました。 –

2

私はそれを得るために掘りもう少し必要がn.m.の答えは、権利でありますなぜ、ここに私が従ったいくつかのリンクがあります:

The CppCoreGuidelines that that "Nonmember operators should be either friends or defined in the same namespace as their operands"why the same namespaceの詳細な説明は次のとおりです。
は多分これthis message from the GCC mailing listはさらに多くの洞察を提供します:GCCの人がここで鍵が名前空間で、より厳密にいくつかの時間イム2016

この問題に対処することを決めたかのように見えます。あなたは友人の定義に直接実装を置く場合、これは、単純に取得すること

namespace foo 
{ 
    struct bar 
    { 
     friend std::ostream & operator<< (std::ostream &, bar const &); 
    }; 

    // Implementation 
    std::ostream & operator<< (std::ostream & o, foo::bar const &) 
    { return o; } 
} 

注:それはこのような名前空間のfooの代わりに、外内オペレータ< <を、定義されている場合あなたのコードはOKだろうthis SO answer to a similar questionに示すように、

very similar questionへの別の、非常に精巧な答えです。私が同じ問題を解決しようとしたときには助けになりました。(gcc 7はずっと古いバージョンでもうまくコンパイルされたコードを手に入れました) barは、名前空間xxxで宣言されていないので、あなたは(あまりにも打ち鳴らすと)コンパイルエラーになります

namespace xxx { 
    struct foo { 
     friend void bar(); 
    }; 
} 

int main() { 
    xxx::bar(); 
} 

関連する問題