Posted at

ADLはクラステンプレートのインスタンス化とは無関連

More than 3 years have passed since last update.


まずADLって何よ?

関数呼び出し式において、関数名についてスコープ解決演算子 :: を使用しなかった時、実引数の存在する名前空間が探索される。 1

この時、引数がクラステンプレートであれば、テンプレート引数の型が定義されている名前空間も探索対象となる。

#include <iostream>

#include <utility>
using namespace std;
namespace ns
{
struct s{};
void swap( s, s ) { cout << "ns" << endl; }
}

int main()
{
using std::swap;
ns::s v;
swap( v, v );
}


クラステンプレートのインスタンス化

クラステンプレートをインスタンス化する時、そのテンプレート引数の型の定義が定義されている名前空間を探索対象にはしない。

何故なら、関数呼び出し式ではないからだ。

例えば、以下のコードはビルドが通らない。

#include <limits>

namespace ns
{
template< class C >
struct numeric_limits {};
struct s {};
template<>
struct numeric_limits< s >
{
static constexpr const bool is_exact = true;
};
}

int main()
{
using std::numeric_limits;
static_assert( numeric_limits< ns::s >::is_exact, "test" );
}


どうすればいいのか

臆せず堂々と特殊化しろ。名前空間 std だろうがテンプレートの特殊化なんだ、未定義の動作にならないはずだ! 2


参考





  1. 大幅に簡略化して書いている。厳密な定義ではない。 



  2. 名前空間 std 内に名前を定義する事はオーバーロードを含め、その動作は定義されない。ただし、テンプレートの特殊化は例外である。