2017-03-09 27 views
9

私はこのコードを持っている:驚きとこの特定のケースでテンプレートパラメータが必要なのはなぜですか?

struct Base {}; 

template<typename T> 
struct Foo : Base {}; 

struct Bar { 
    template<typename T> //   v--- What's happening here? 
    Bar(T foo) : baz{std::make_unique<Foo>(foo)} {} 

    std::unique_ptr<Base> baz; 
}; 

を、GCCとクランを受け入れ、それをコンパイルします。それはFooのテンプレートパラメータを推定するようですが、それは意味をなさないでしょう。テンプレートテンプレートパラメータをとるstd::make_uniqueの過負荷がなくても、コンパイラはそれをどのように受け入れますか? Live example

+3

エラー...できれば、そのコンストラクタで 'Bar'オブジェクトを作成してみてください。コンパイラがコードを受け入れるかどうかを教えてください。 – WhiZTiM

+0

@WhiZTiMコードを拒否します。私はまだ両方のコンパイラが不一致のテンプレートパラメータの型について不平を言っていないことは本当に奇妙であることがわかります。 –

答えて

8

テンプレートは関係なく、引数が供給されているものをテンプレート、常に無効ではないいくつかの状況がありますが、コンパイラは、そのを把握することができません、それはすべてのを代入しようとする能力を持っていないため、テンプレート引数の可能なセット。標準([temp.res]/8)によれば、有効な特化は テンプレートのために生成することができない、そのテンプレートがインスタンス化されていない場合

、テンプレートが悪い形成されており、いかなる診断 不要。コンパイラは賢いこととが有効な分業が存在しないことを証明し、コンパイルエラーを生成するために許可されているが、それも十分にスマートではない、とコンパイルエラーを生成しないために許可されていますことを意味

。もちろん、テンプレートがインスタンス化されると、コンパイラはエラーを診断する必要があります。

テンプレート引数なしでテンプレートの名前を使用することは違法ではありません。コンパイラが引数を推論できる状況がいくつかあります。例えば:あなたのコードで

template <class T> 
void foo(T x); 

int main() { 
    void (*p)(int) = foo; // p points to foo<int> 
} 

、それはあなたがテンプレート引数を推定することができない状況でFooを使用していたことが判明しました。コンパイラがよりスマートならば、それは分かりました。しかし、彼らはそれを把握することができなかったという事実はあなたのコードが正しいことを意味しません。

+1

ニースのコードスニペットは、このようなコードが有効で、テンプレートパラメータがそのようなコンテキストで推測できるとは考えていませんでした。 – vsoftco

4

これは、コード内のどこかから呼び出されるまで、実際にはC++がテンプレート関数を作成しないためです。この例では、コードがBarを作成しようとしていないので、テンプレートone-arg Barコンストラクタは生成されないため、コンパイラはコードが正しいかどうかを確認する必要はありません。

テンプレート関数は、使用されるとすぐにコンパイラによって生成され、渡された型に基づいて生成されます。あなたはそのようなBar作成しようとしたのであれば、:それは今のコードが間違っている知っているので

error C2955: 'Foo' : use of class template requires template argument list 

Foo<int> f; 
Bar b = Bar(f); 

をコンパイラがコンストラクタを生成するなどのエラーで失敗しようとします。

もしこれについて考えるなら、これはどのように動作しなければならないのですか?C++ではテンプレート型に制約を付けることができないため、コンパイラは可能なすべてのテンプレート型を試して、関数に構文エラーがあります。

+0

コンパイラはいくつかのテンプレートチェックも実行しますが、この場合は実際にチェックは実行されません。ルールは実際にはかなり複雑です。詳しい説明は[C++ Templates:A complete guide](https://www.amazon.com/Templates-Complete-Guide-David-Vandevoorde/dp/0201734842)を参照してください。 – vsoftco

+0

はい、sfinaeでconceptをエミュレートすることで、テンプレートパラメータを制約できます。 –

+1

@GuillaumeRacicotこれは、テンプレート関数のインスタンス化に使用できる型を制約することはできません。特定のオーバーロードでは構文エラーを作成することしかできないため、そのインスタンス化にはオーバーロード解決の優先順位が低くなります。任意の型を任意のテンプレート型に対して使用することができるので、コンパイラーは任意の型を可能な候補として考慮する必要があります。これは、私が言ったように、特定のインスタンス化が選択される前に構文エラーをチェックすることが不可能になります。 –

関連する問題