2011-04-18 21 views
8

これはGCC 4.4でコンパイルできないのはなぜですか?名前空間の関数テンプレートのオーバーロード

template<typename T> 
class A { 
public: 
    void foo() { 

    } 

private: 
    T x; 
}; 

namespace Ns { 
template<typename T> 
void do_it (A<T> a) { 
    a.foo(); 
} 
}; 

template<typename T> 
void myfun (T x) { 
    Ns::do_it (x); 
} 

template<typename T> 
class B { 
public: 
    void bar() { 

    } 

private: 
    T x; 
}; 

namespace Ns { 
template<typename T> 
void do_it (B<T> b) { 
    b.bar(); 
} 
}; 

int main() { 
    A<int> a; 
    B<int> b; 

    myfun (a); 
    myfun (b); // error: no matching function call to do_it(B<int>&) 

    return 0; 
} 

do_itの名前空間と関係があります。その周りの名前空間を削除すると、コンパイルされます。

背景:私は、多くの異なるコンテナクラスで使用することができる機能のセットを構築しています。さまざまなインターフェイスを一様に処理するために、私は各コ​​ンテナクラスに対して多重定義されたフリースタンディング関数を使用します。これらの関数は、グローバル名前空間を混乱させないために、名前空間に入れなければならない。 B用

定義がそのように並べ替えのためのものとは異なるヘッダ・ファイルから来ると考えなければならないことは選択肢ではありません。

+0

タイプミスです! はHTMLによって飲み込まれました。 –

+0

VS 2010は上記のコードをコンパイルしていますが、これは正しいと思いますが、これは難しい例です。ニースの質問! –

+0

VS2008と同じですが、私はそれをチェックしました。これはGCCのバグでしょうか、それともMicrosoftの解釈とは違うのでしょうか?それが名前空間なしで動作するという事実は、それがバグであることを指摘するだろうか? –

答えて

6

理由は、コールの時点でADLだけが実行されるためです。他の関数参照は、myfun関数テンプレートの定義でのみ行われます。

そして、その定義の文脈では、のうち、A<int>を受け入れる過負荷のみが宣言されています。

編集:あなたは、このための標準の参照を持つようにしたい場合は、[temp.dep.candidate]を参照し、[temp.res] P1。

+0

名前空間を使用してこれを解決する標準的な方法はありますか? –

+2

@Markネームスペース 'Ns'の関数を考慮したい場合は、そのネームスペースで定義されたダミークラスから' B 'を派生させることができるので、ADLは' Ns'ネームスペースを調べます。あるいは、テンプレート引数を 'B 'に渡して、生成された特殊化を 'Ns 'に関連付けることができます。たとえば、 'B >'(ADLAssociatorは 'T t;'しか格納しない小さなクラスのテンプレートかもしれません)。あるいは、それらのアソシエータクラスを追加の仮引数として渡します: 'B '。これには多くのオプションがあります。最もクリーンなのは、クラスから 'B'を派生させたり、' NS'で定義したように思えます。 –

+5

空き関数を静的なクラスメンバに変更する方法は? 'namespace Ns {template struct dispatch; } '特殊を追加、それぞれの新しいタイプ、次いで、(フロントそれを宣言):'名前空間Ns個{テンプレート構造体ディスパッチ< B> {静的ボイドdo_it(B X){x.bar();}} } '、テンプレートを持っています void myfunc(T t){Ns :: dispatch :: do_it(t); } ' –

関連する問題