先人たちが書いたコードからは学びが多いものです。
みんな大好きboostのnoncopyableのソースコードを読んでみましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
namespace boost { // Private copy constructor and copy assignment ensure classes derived from // class noncopyable cannot be copied. // Contributed by Dave Abrahams namespace noncopyable_ // protection from unintended ADL { class noncopyable { protected: noncopyable() {} ~noncopyable() {} private: // emphasize the following members are private noncopyable( const noncopyable& ); const noncopyable& operator=( const noncopyable& ); }; } typedef noncopyable_::noncopyable noncopyable; } // namespace boost |
8行目のコメントが興味深いですね。
protection from unintended ADL(思いがけないADLの防止)
どういう意味でしょうか。
ご存知のとおり、ADLでは予期せぬネームスペースまで検索の対象になることがあり、時として不幸な不具合の温床になっていまうことがあります。
それというのも、ADLによって、検索されるネームスペースに実引数の名前空間が暗黙に含まれる為なのですが、このboostのコードではその予防策が講じられているというわけです。
21行目で
1 |
typedef noncopyable_::noncopyable noncopyable; |
とあります。
この一行のtypedefにより、本来boost::noncpyable_::noncopyableというアクセスをboost::noncopyableと書くことができるようになります。
しかし、実際のnoncopyableはnoncopyable_というネームスペースに存在している為、ADLによってboostネームスペース全てが検索候補になってしまうことを防いでいるのです。
これがADL Firewallという手法です。
このようにネストしたネームスペースに型を閉じ込めて、ネームスペースごとエイリアスを付けることで、アクセスしやすくするのですが、inline namespace ではADL対策になりませんので気をつけて下さい。
inline namespace はADL対策にはなりません!
大事なことなので2回言いました。
余談
このADL Firewallという言葉は某コンソールゲーム機のSDKを読んでいて初めて知ったのですが、それ以外の場所で滅多にお目にかからない言葉なので、あまりメジャーな呼び方では無いのでしょう。とはいえ、このようなADL対策について一言で言い表す表現を他に知らないので某SDKにならってADL Firewallと呼ぶようになりました。
まとめ
- 予期せぬADLの防止は型を別の名前空間に移して宣言する
- inline namespaceはADL対策にはならないので注意