ADLとET

両方ともわりと専門的(?)な用語なので意味不明なタイトルになっているかもしれないが(ry
ADLは"argument dependent lookup"でETは"Expression Template"のことである。えっと、解説がちょっと大変なのでお世話になっておりますfaith_and_braveのアキラさんの記事を貼っておきます(^^;
ADL id:faith_and_brave:20071219
ET id:faith_and_brave:20081003

で、この二つ、何の関係があるかというと、ADLを知らなかったがためにETの実装に苦労したことがあるんですorz

ETはその性質上、グローバルにoperatorを多重定義し引数をテンプレートにします。

template <class L, class R>
inline Plus<L, R> operator+(const L& l, const R& r)
{
    return Plus<L, R>(l, r);
}

こいつが厄介で、引数が両方ともテンプレートなのでどんな型でも当てはまってしまう。おかげで関係ない型までマッチングして変なコンパイルエラーが出たりすることがあります(や、私の実装が悪かっただけかもしれないけど)
haskellの型クラスみたいなのが欲しいと思った瞬間でした。

template <class L, class R>
class Plus : public Vector{
	//・・・中略
};

template <class (Vector L) => L, class (Vector R) => R >
inline Plus<L, R> operator+(const L& l, const R& r)
{
    return Plus<L, R>(l, r);
}
//↑テンプレート引数にVector型を継承した型以外をマッチングさせない

ないものねだりしても仕方が無いので以下のようにマッチングを制御しました

template <class R>
inline Plus<Vector, R> operator+(const Vector& l, const R& r)
{
    return Plus<Vector, R>(l, r);
}
template <class L_L, class L_R, class R>
inline Plus<Plus< L_L, L_R >, R> operator+(const Plus< L_L, L_R >& l, const R& r)
{
    return Plus<Plus< L_L, L_R >, R>(l, r);
}

片方を使う型を入れてオーバーロードすることにより関係ない型を弾きました。しかしこれ実際にはPlus以外にも結構たくさんあったのですごいことになりました。まあマクロを駆使して演算子を量産したのでサイズは抑えましたがもはや暗号でしたorz


しかし、ADLを使えば簡単に解決できるということに最近気が付きました。
これらのライブラリをまるごと名前空間でくくってしまうだけです。例えば、ETという名前空間で囲ったとする。

ET::Vector x, y, z, t;
t = x + y + z;
//↑+演算子はADLのおかげてET::operator+とか書かなくてよい!

しかしこれだと、使う側がいつもET::とか書かなくてはいけなくなる。using namespace ET;なんて書いたらまた+演算子が外に出てしまう。ので、ET::Vectorだけを外に出せば良い。

using ET::Vector;

Vector x, y, z, t;
t = x + y + z;

このusingはライブラリ側で宣言してもいいかもしれません。


ひょっとしたら定番の技なのかもしれませんが私には感動の一瞬でした(涙