2016-08-08 9 views
4
struct Value { 
    using a_type = int; 
    a_type f() { return 1; } 
}; 

template<typename T> 
struct Wrapper { 
    T t; 
    auto call_f() { return t.f(); } 
}; 

int main() { 
    Wrapper<Value> w; 
    Wrapper<int> w2; 
    w.call_f(); 
} 

これはClangとGCCでうまくコンパイルされます。戻り値の型がWrapper<int>::call_f()である場合でも、Wrapper<int>がインスタンス化されます(int::f()はありません)。 w2.call_f()が呼び出されたときだけ失敗します。未定義のメンバー関数の戻り値の型を持つテンプレートのインスタンス化

この部分はC++標準であり、すべてのコンパイラで動作することが期待できますか?

答えて

11

はい、これはC++標準の一部です。

テンプレートのインスタンス化のルールは長くて複雑ですが、短いバージョンでは、テンプレートクラスのメンバー関数が必要なときにインスタンス化されるだけです。何もそれを呼び出したり、ポインタを取得しようとしたり、明示的にインスタンス化したりしていない場合は、インスタンス化されず、コードも整形式になります。

@dypが指摘するように、それがクラス定義がインスタンス化されるときにインスタンス化されるメンバ関数([temp.inst]/1)のみ宣言であるが、機能定義である場合、戻り型推論にのみ行われますインスタンス化されました([dcl.spec.auto]/12)。

これは、テンプレートのオーバーヘッドを最小限に抑え、タイプ要件を許容する上で非常に役立ちます。それはあなたがこのような何か行うことができます。この機能です:デフォルト-構成可能であることをTを必要とする(例えば、resize

struct Foo { 
    //no default constructor 
    Foo(int); 
}; 

std::vector<Foo> foos; 

一部std::vector機能を、しかし限り、あなたは、あなたがまだ使用できるこれらの機能を呼び出すことはありませんとしてstd::vectorのその他の機能

2

はい、標準によって保証されています。 Wrapper<T>::call_f()は、呼び出されたときにのみ暗黙的にインスタンス化されます。

$14.7.1/2 Implicit instantiation [temp.inst]

クラステンプレートまたはメンバー・テンプレートのメンバーは、明示的にインスタンス化または明示的に特化されている場合を除き分業が必要となるコンテキストの中で参照されている場合、メンバーの専門が暗黙的にインスタンス化されますメンバー定義が存在する。

$14.7.1/8 Implicit instantiation [temp.inst]

実装は、暗黙的に関数テンプレート、変数テンプレート、メンバテンプレート、非仮想メンバ関数、メンバクラス、クラスの静的データメンバをインスタンス化してはなりませんテンプレート、またはステートメント([stmt.if])のconstexprのサブステートメントのような、インスタンス化が必要な場合を除きます。

関連する問題