

次のようなコードを考えます。  
1\. inline指定されたテンプレート関数func  
2\. funcを通してクラスBのメンバにアクセスするクラスA  
3\. クラスBの実装はクラスAより後にある

[code]

    template<class T>
    inline func()
    {
        cout << T::GetClassName() << endl;
    }
    
    class B;
    class A {
        void Run(){
            func<B>();
            //::B::GetClassName(); error
        }
    };
    
    class B {
    public:
        static string GetClassName(){
            return "B";
        }
    };
    
[/code]

この場合、  
インライン展開されたテンプレート関数は、シンボルGetClassNameを解決するため、クラスBの完全な型情報が必要だと思うのですが、C++11の規格ではどうなってるでしょうか？

ちなみにgcc4.8で試したところ、上記のコードはコンパイルが通りましたが、コメントアウト箇所を有効にしたところ、完全な型情報を求められコンパイルエラーになりました。


CC BY-SA 3.0
2016-02-16T03:16:27.593
22145
2016-02-19T08:08:02.437
2016-02-16T03:23:33.460
3605
7566
question
c++ c++11
テンプレートのインライン展開時におけるシンボル解決


**[2016-02-18 01:57注記: 以下の内容は規格書の読み間違いの可能性が高いです。コメントも参照して下さい]**

`A::Run` 中で、 `func<B>()` が問題なく呼び出せることはC++規格の範囲内であると思います。

まず、ISO/IEC 14882:2011 14.6.4.1 Point of instantiation 第6段落にはこうあります。

> The instantiation context of an expression that depends on the template
> arguments is the set of declarations with external linkage declared prior to
> the point of instantiation of the template specialization in the same
> translation unit.

この段落では、テンプレート引数に依存する式 (今回の質問では `cout << T::GetClassName() << endl;`)
のインスタンス化の際、インスタンス化された地点 ( _the point of instantiation_ \-- 今回の質問では `func<B>()`
を呼び出した箇所) 以前に宣言されたものが使えます (かなり端折り＆意訳しているので、正確なところは引用した原文をどうぞ)。

これだけでは、`func<B>()` が呼び出された箇所の前には `B::GetClassName`
の宣言がないため、むしろ不適合に読めますが、続く第7段落にはこう書かれています。

> A specialization for a function template, a member function template, or of
> a member function or static data member of a class template may have
> multiple points of instantiations within a translation unit, and in addition
> to the points of instantiation described above, for any such specialization
> that has a point of instantiation within the translation unit, **the end of
> the translation unit is also considered a point of instantiation**.

キモとなる部分を強調しましたが、こちらもざっくり説明すると、関数テンプレートなどの特殊化 (`specialization`)
においては、翻訳単位の終端部分をインスタンス化された地点とみなすとあります。第6段落と合わせると、翻訳単位全体の宣言がインスタンス化する際に使えることになります。  
そのため、テキストの位置的には、`func<B>()` の呼び出しが `B::GetClassName` の宣言の前にありますが、特殊化の際には、
`B::GetClassName` が含まれます。


CC BY-SA 3.0
2016-02-16T12:13:28.573
22174
2016-02-17T16:56:51.700
2016-02-17T16:56:51.700
7831
7831
22145
answer