名前空間にNB::B<T>
非テンプレート クラスから派生したテンプレート クラスがあります。テンプレート引数のインスタンスで関数を呼び出すテンプレート関数です。具体的には、 ADL を使用して の baseの名前空間で定義されているものを見つけたいと考えています。完全な例は次のとおりです。NA::A
act<T>
add_ref
act<NB::B<int>>
add_ref
NB::B
template<class T>
void act() {
T* p = 0;
add_ref(p); // the failing line
}
namespace NA
{
struct A { };
// I want ADL to find this:
void add_ref(A* p) {
}
}
namespace NB
{
// template class with non-template base
template <class T>
struct B: NA::A { };
typedef B<int> Bi;
// using NA::add_ref; // fixes the problem
}
int main()
{
act<NB::Bi>();
}
これはgcc
(4.7.0) で問題なくコンパイルされます。しかもComeau
オンラインで。ただしclang
、(3.1) は失敗します。
a.cpp:4:3: error: use of undeclared identifier 'add_ref'
同時に、規格には次のように書かれています。
3.4.2/2 …</p>
— T が template-id の場合、関連付けられた名前空間とクラスは、テンプレートが定義されている名前空間です。メンバー テンプレートの場合は、メンバー テンプレートのクラス。テンプレート型パラメーター (テンプレート テンプレート パラメーターを除く) に提供されるテンプレート引数の型に関連付けられた名前空間とクラス。テンプレート テンプレート引数が定義されている名前空間。テンプレート テンプレート引数として使用されるメンバー テンプレートが定義されているクラス。
驚いたことに、テンプレートのベースは、関連付けられた名前空間へのパスとしてリストされていません。したがってclang
、 の動作は正しいように見えます。そしてComeau
とgcc
は間違ったプログラムを受け入れています。
同時に、が引数の名前空間に3.4.2/3
ある状態は効果がありません:using
関連付けられた名前空間を考慮する場合、検索は、関連付けられた名前空間が修飾子として使用されるときに実行される検索と同じです (3.4.3.2)。
— 関連する名前空間の using ディレクティブは無視されます。
しかし、コメントを外すと、using NA::add_ref
行clang
は喜んでテストをコンパイルします。
私の例を実用的な観点から考えると、これはbase から派生した、 was 、 was 、wasact
のメソッドであると考えることができます。boost::intrusive_ptr
add_ref(A*)
intrusive_ptr_add_ref(CBase*)
B
CBase
これに関して、いくつか質問があります。
私
clang
のテストプログラムを拒否するのは正しく、標準に従わないのは正しいgcc
ですComeau
か?標準がそのような非実用的な動作を指定する理由はありますか (テンプレート クラス ベースを関連付けられた名前空間として許可しません)。
という理由でディレクティブを
clang
使用してテスト プログラムを受け入れるのは間違っていますか?using NA::add_ref
3.4.2/3
バグを報告する必要がありますか? :)
PS clang Language Compatibility FAQを読みましたが、回答が見つかりませんでした。