8

名前空間にNB::B<T>非テンプレート クラスから派生したテンプレート クラスがあります。テンプレート引数のインスタンスで関数を呼び出すテンプレート関数です。具体的には、 ADL を使用して の baseの名前空間で定義されているものを見つけたいと考えています。完全な例は次のとおりです。NA::Aact<T>add_refact<NB::B<int>>add_refNB::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、 の動作は正しいように見えます。そしてComeaugccは間違ったプログラムを受け入れています。

同時に、が引数の名前空間に3.4.2/3ある状態は効果がありません:using

関連付けられた名前空間を考慮する場合、検索は、関連付けられた名前空間が修飾子として使用されるときに実行される検索と同じです (3.4.3.2)。

— 関連する名前空間の using ディレクティブは無視されます。

しかし、コメントを外すと、using NA::add_refclangは喜んでテストをコンパイルします。

私の例を実用的な観点から考えると、これはbase から派生した、 was 、 was 、wasactのメソッドであると考えることができます。boost::intrusive_ptradd_ref(A*)intrusive_ptr_add_ref(CBase*)BCBase

これに関して、いくつか質問があります。

  1. clangのテストプログラムを拒否するのは正しく、標準に従わないのは正しいgccですComeauか?

  2. 標準がそのような非実用的な動作を指定する理由はありますか (テンプレート クラス ベースを関連付けられた名前空間として許可しません)。

  3. という理由でディレクティブをclang使用してテスト プログラムを受け入れるのは間違っていますか?using NA::add_ref3.4.2/3

  4. バグを報告する必要がありますか? :)

PS clang Language Compatibility FAQを読みましたが、回答が見つかりませんでした。

4

1 に答える 1

6

基本的にC++11であり、編集上の小さな変更が加えられたn3337から、3.4.2/2は次のようになります。

関数呼び出しの引数タイプTごとに[...]名前空間とクラスのセットは次のように決定されます。[...]

  • Tがクラスタイプ(ユニオンを含む)の場合、関連するクラスは次のとおりです。クラス自体。メンバーであるクラス(ある場合)。およびその直接および間接の基本クラス。関連する名前空間は、関連するクラスがメンバーである名前空間です。さらに、Tがクラステンプレートの特殊化である場合、...

そして、それはあなたが質問に投稿したのと基本的に同じ引用で続きます。ここでの重要な違いはさらにです。つまり、引用した(そして私が省略した)リストは、すでに述べた名前空間に追加され、基本クラスがメンバーである名前空間が含まれています。

  1. Gccとcomeauは正しく、clang++はコードを拒否するのに間違っています。

  2. <適用されません>

  3. Clang ++は、。なしで拒否するのは間違っていusing NA::add_refます。

  4. はい、おそらくバグを報告する必要があります。すでに報告され、修正されているようです。

于 2012-07-23T19:37:52.447 に答える