2016-11-08 14 views
3

私は型の列挙型を持っていて、型名を出力するために "to_string"関数を使いたいので自分の名前空間に書きました。問題は、to_stringを呼び出すためにネームスペース内の他の関数、例えばint(enumの一部ではないint)がカスタムto_stringを見つけて、enumの無効な初期化についてエラーを出していることです。コンパイル時にenumクラスをintから初期化しようとしています

to_stringではなくstd :: to_stringを明示的に呼び出すことができますが、より良い方法があると思います。私は間違って何をしていますか?

Hereはサンプルコードです:

#include <iostream> 
#include <string> 

namespace other { 
    enum class Type { 
     Type1, 
     Type2 
    }; 

    std::string to_string(const Type& type) { 
     switch(type) { 
      case Type::Type1: 
       return "Type1"; 
       break; 
      case Type::Type2: 
       return "Type2"; 
       break; 
      default: 
      {} 
     } 

     return "Unknown"; 
    } 

    void run() { 
     using namespace std; 
     cout << string("Type: ") + to_string(Type::Type1) << endl; 
     cout << string("int: ") + to_string(42) << endl; // this one generates compile-time errors 
    } 
} 

int main() { 
    other::run(); 

    using namespace std; 
    cout << string("int: ") + to_string(42) << endl; // This one is ok 

    return 0; 
} 
+0

私は物事を見ています...もっと具体的にすることができれば、それをしてください。例えば ​​'run()'の中では、 'other :: to_string'と' std :: to_string'とタイプして、それを編集する次の貧しい人が私の意図したものを正確に知るようにします。良い質問ですが、以前はネームスペースを隠す/過負荷とは考えていませんでした。 – Matt

答えて

3

これは、名前空間の微妙な規則を伴う難しい状況です。

namespace b { 
    void f(int) { } 
} 

namespace a { 
    using namespace b; 

    void f(char) { } 

    void g() 
    { 
    f(5); // calls f(char) 
    } 
} 
ここでの問題は、我々は using namespace bを持っているにもかかわらず、彼らは、ルックアップの目的のための共通の名前空間(グローバル)で宣言されたかのように、B内部の宣言が扱われることである

のは、単純な例を考えてみましょう

(C++ 14 7.3.4/2)

使用ディレクティブは指名名前空間内の名前は、ディレクティブを使用して が使用ディレクティブ後に表示された範囲で使用することができることを指定します。修飾されていない名前検索(3.4.1)では、名前は のように表示され、あたかも最も近い囲みネームスペースに指定されています。このディレクトリにはusingディレクティブとという名前のネームスペースが含まれています。 [注:この文脈において、「含有する」とは、「直接的または間接的に含有する」ことを意味する。 - 末尾 注]

このため、参照のために、名前空間bの名前はグローバル名前空間にあるものとして扱われます。つまり、名前空間内のf(char)が名前空間内にf(int)を隠すことになります。

(C++ 14 3.3。名前空間名で修飾名のルックアップ中に10/4)

、そうでない場合は使用してディレクティブによって可視 を含む名前空間に同じ名前と宣言によって非表示にすることができます行われることになる宣言 usingディレクティブ。 (3.4.3.2)参照。あなたの例では

std::to_string(int)が隠されているので、other::run()to_string(42)への呼び出しは、other::to_stringを見つけるでしょう。

+0

"lower"ネームスペースの関数は、名前は同じですか?署名は異なっていますが?コンパイラがシグネチャを一致させようとしてもエラーを見つけられず、引き続き有効なマッチを見極めるための実用的な理由はありますか? – ryan0270

+0

@ ryan0270:はい、スコープを超えて作業がオーバーロードされるのはあまりにも混乱していると考えられました。詳細はこちら:http://stackoverflow.com/a/1629074/951890 –

4

あなたが明示的に "過負荷セット" see wandbox exampleに持って帰りたいと思う機能内容を指定する必要があります。理由はということです

void run() { 
    using namespace std; 
    using std::to_string; 
    cout << string("Type: ") + to_string(Type::Type1) << endl; 
    cout << string("int: ") + to_string(42) << endl; 
} 

ADLはディレクティブの使用を無視します。 3.4.2 [basic.lookup.argdep]を参照:関連付けられた名前空間を修飾子として使用する場合

関連付けられた名前空間を考慮すると、検索が実行ルックアップと同じである(3.4.3.2)をただし、以下を除きます。 - 関連する名前空間内のusingディレクティブはすべて無視されます。

詳細情報はin this questionです。

+0

なぜそれをする必要がありますか?コンパイラがintからTypeへの変換が有効でないことを検出してから、次に有効な別のシグネチャを探す(そしてstd :: to_stringで終わる)べきではないでしょうか? – ryan0270

+0

'std :: to_string'を明示的に呼び出すと、このメソッドは名前の参照でより良く一致します。これがなければ、名前空間階層の各ステップごとに(おおまかに言えば)支払うことになります。輸入では、無料で利用できます。 – m8mble

+0

申し訳ありませんが説明を提供していません、私は引用する良いソース/標準部分を見つけようとしています。 [こちらを見てください](http://stackoverflow.com/questions/27544893/why-doesnt-a-using-directive-affect-adl) –

関連する問題