2011-02-23

不完全型と暗黙のインスタンス化

以下のコードはwell-formedである。

template < typename T >
struct A
{
    T member ;
} ;

struct B
{
    A<B> * ptr ;
} ;

int main()
{
    B b ;
    b.ptr->member ;
}

クラスBの定義内では、Bは不完全型である。したがって、A<B>型は不完全型である。もし、クラスBの定義内で、インスタンス化が起こるのならば、このコードはill-formedである。しかし、このコードは、実際にはwell-formedである。何故か。

暗黙のインスタンス化は、完全なオブジェクトの型が必要になった地点で行われる。完全なオブジェクトの型でなくても、プログラムに影響を与えない場合は、インスタンス化は行われない。では、上記のコードにおけるA<B>のインスタンス化を発動させる行はどこだろうか。当ててみてほしい。

// Point of Instantiationを答えなさい
template < typename T >
struct A
{
    T member ;
} ;

struct B
{
    A<B> * ptr ; // #1
} ;

int main()
{
    B b ; // #2
    b.ptr ; // #3
    b.ptr->member ; // #4
}

答えは、#4である。何故ならば、ある型へのポインターは、ある型が完全型でなくてもかまわないからだ。したがって、#1はA<B>のPoint of Instantiationではない。また、#2、#3も、A<B>の中身を参照していないので、Point of Instantiationではない。インスタンス化の発動は、実際に完全型が必要な、#4の時点で行われる。

テンプレートのインスタンス化が起こらなければ、不完全型であっても構わない。テンプレートのインスタンス化が起こる地点で、完全型になっていればいいのだ。

3 comments:

kariya_mitsuru said...

今回の例ですが、14.6.4.1 Point of instantiation [temp.point] の 3 から考えると、main の直前になるように思うのですが、いかがでしょうか。

江添亮 said...

ああ、確かに規格上のpoint of instantiationは、その参照されている場所の名前空間スコープですね。

江添亮 said...

今回は、point of instantiationではなく、暗黙のインスタンス化を発動させる部分が問題であるので、本文の方を書き直しました。