クラステンプレートの具現化の位置

初エントリです。


テンプレートのインスタンス化のタイミングが分からない><
興味が沸いたので調べてみた。
本当にあっているのかは分からないけど。

  • 14.7.1 暗黙の具現化

クラステンプレート特殊化が,既に明示的に具現(14.7.2)されているか又は
明示的に特殊化(14.7.3)されている場合を除き,そのクラステンプレート特殊化が,
完全に定義されたオブジェクト型を要求する文脈で使用されるか 又は そのクラス型の
完全性がプログラムの意味に影響を与える場合,そのクラステンプレート特殊化は,
暗黙に具現される。(1)


クラステンプレート特殊化が暗黙に具現されることによって,そのクラスのメンバ関数
メンバクラス,静的データメンバ 及び メンバテンプレートの宣言は,暗黙に具現される。
しかし,それらの定義 又は 省略時実引数は,暗黙に具現されることはない。(2)


クラステンプレートのメンバ 又は メンバテンプレートが,既に明示的に具現されているか
又は 明示的に特殊化されている場合を除き,その特殊化は,そのメンバ定義が要求される
文脈で用いられたときに,暗黙に具現される。(3)

  • 14.6.4.1 具現化の位置

(中略) クラステンプレートのメンバ関数 (中略) の特殊化の具現化の位置は,
その特殊化を参照する,名前空間有効範囲の宣言 又は 定義の直後とする。(4)

翻訳単位の最外側の宣言領域も名前空間となり,大域的名前空間(global namespace)と呼ぶ。
大域的名前空間で宣言された名前は,大域的名前空間有効範囲(大域的有効範囲ともいう)をもつ。
こうした名前の潜在有効範囲は,その宣言位置(3.3.1)に始まり,
その宣言領域である翻訳単位の終わりで終わる。(5)


上記より、次のように解釈される。

namespace ns {
	struct B {};
}

template<typename T>
struct A
{
	void f0(T b) {
		f(b);
	}
};

int main(int, char**)
{
	A<ns::B> a;    // (1) クラスA<ns::B>の具現化が要求される。
	               // (2) A<ns::B>::f0(ns::B)の宣言は暗黙に具現されるが、
	               //     定義は暗黙に具現されない。
	a.f0(ns::B()); // (3) A<ns::B>::f0(ns::B)の具現化が要求される。
	               // (4) (3)での具現化の要求は、ここの名前空間有効範囲
	               //     (ここでは大域的名前空間)が終わるまで処理されない。
	return 0;
}

namespace ns {
	void f(ns::B) {}
}

// (5) 大域的名前空間の終わり(翻訳単位の終わり)。
//     ここで、A<ns::B>::f0(ns::B)が具現化される。
//     すでに、ns::f(ns::B)は可視である。


元エントリでは触れていませんが、A::f0(ns::B)内で、ns名前空間にあるはずのf(ns::B)を
修飾無しに呼び出せているのを不思議に思う方もいるかもしれません。

それは、仮引数bがns名前空間のものなので、この関数内ではns名前空間がスコープに入るからです。
[Exceptiona C++ 項目31]