2012年1月2日月曜日

ADL

ADLとは

Argument Dependent name Lookupの略で、引数によって関数を探索する仕組みのことです。ADLは、あるオブジェクトを非メンバー関数で使用する場合に、メンバー関数と同じように簡単に使用できるようにするために存在します。

次に例を示します。名前空間Aに存在するクラスBには加算演算子の非メンバー関数が定義されています。

namespace A {
  class B {
    // class Bの定義
  };
  B operator+(const B&, const B&);
  void func(const B&);
}

この加算演算子を別の名前空間で使用する場合、ADLが役に立ちます。

namespace C {
  void func() {
    B b1, b2;
    // ADLが使える場合。
    B b3 = b1 + b2;
    // ADLが使えない場合。
    B b4 = A::operator+(b1, b2);
    func(b4); // A::func(const B&)が呼び出されます。
  }
}

ADLの厄介なところ

とても便利なADLですが、非常に厄介な面もあります。意図しない関数が呼び出されるケースがあるからです。

namespace A {
  template<typename T>
  class B {
  };
}
namespace C {
  class D {
  };
  template<typename T> void print(T& t) {
    std::cout << "C::print()" << std::endl;
  }
}
int main() {
  A::B<C::D> b;
  print(b);
}

上記のサンプルを実行すると、"C::print()"が出力されます。テンプレートと名前空間が組み合わさると、ADLは非常にわかりづらいバグを生み出します。

また、名前空間Aにprint関数が存在すると、コンパイル時にA::print()かC::print()のどちらを参照するべきか、曖昧であるとエラーになります。

0 件のコメント:

コメントを投稿