2016年の賢明な時代に、この質問が出されてから2つの新しい標準が登場し、すぐに新しい標準が登場したため、C ++ 17標準をサポートするコンパイラがコードをそのままコンパイルすることを知っておくことが重要です。
C ++ 17でのクラステンプレートのテンプレート引数の控除
ここに(承認された回答のOlzhas Zhumabekによる編集の礼儀)は、規格への関連する変更を詳述した論文です。
他の回答からの懸念への対処
現在の最高評価の答え
この回答は、「コピーコンストラクターとoperator=
」は正しいテンプレートの特殊化を知らないことを指摘しています。
標準のコピーコンストラクターoperator=
が存在し、既知のテンプレートタイプに対してのみ存在するため、これはナンセンスです。
template <typename T>
class MyClass {
MyClass(const MyClass&) =default;
... etc...
};
// usage example modified from the answer
MyClass m(string("blah blah blah"));
MyClass *pm; // WHAT IS THIS?
*pm = m;
私はコメントで述べたようにここでは、存在しない理由のためのMyClass *pm
推論の新しいフォームの有無にかかわらず、法的宣言すべき:MyClass
タイプではありません(それはテンプレートだ)、それはのポインタを宣言しても意味がありませんので、タイプMyClass
。この例を修正する方法の1つを次に示します。
MyClass m(string("blah blah blah"));
decltype(m) *pm; // uses type inference!
*pm = m;
ここでpm
は、すでに正しいタイプであるため、推論は簡単です。さらに、コピーコンストラクターを呼び出すときに誤って型を混在させることはできません。
MyClass m(string("blah blah blah"));
auto pm = &(MyClass(m));
ここでpm
は、のコピーへのポインタになりますm
。ここでMyClass
は、からコピーが構築されています。m
これはタイプですMyClass<string>
(存在しないタイプではありませんMyClass
)。したがって、pm
のタイプが推定される時点では、のテンプレートタイプ、つまりのテンプレートタイプがm
であることを知るのに十分な情報pm
がありstring
ます。
さらに、次の場合は常に コンパイルエラーが発生します。
MyClass s(string("blah blah blah"));
MyClass i(3);
i = s;
これは、コピーコンストラクターの宣言がテンプレート化されていないためです。
MyClass(const MyClass&);
ここで、copy-constructor引数のtemplate-typeは、クラス全体のtemplate-typeと一致しています。すなわち、時にMyClass<string>
インスタンス化され、MyClass<string>::MyClass(const MyClass<string>&);
それをインスタンス化され、そしてときにMyClass<int>
インスタンス化され、MyClass<int>::MyClass(const MyClass<int>&);
インスタンス化されます。明示的に指定されていないか、テンプレート化されたコンストラクターが宣言されていない限り、コンパイラーがをインスタンス化する理由はありませんMyClass<int>::MyClass(const MyClass<string>&);
。これは明らかに不適切です。
CătălinPitișによる回答
Pitişは推測する例を示しますVariable<int>
とVariable<double>
、次に述べ、:
2つの異なる型(変数と変数)のコードに同じ型名(変数)があります。私の主観的な観点から、それはコードの可読性にかなり影響します。
前の例で述べたように、新機能により構文的には1つのように見えますVariable
が、それ自体は型名ではありません。
次に、ピチッチは、適切な推論を可能にするコンストラクターが提供されない場合にどうなるかを尋ねます。答えは、推論はコンストラクター呼び出しによってトリガーされるため、推論は許可されないということです。コンストラクタ呼び出しがなければ、推論はありません。
これは、foo
ここで推定されたのバージョンを尋ねるのと同じです。
template <typename T> foo();
foo();
答えは、述べられた理由により、このコードは違法であるということです。
MSalterの回答
これは、私が知る限り、提案された機能に関する正当な懸念を提起する唯一の答えです。
例は次のとおりです。
Variable var(num); // If equivalent to Variable<int> var(num),
Variable var2(var); // Variable<int> or Variable<Variable<int>> ?
重要な問題は、コンパイラーがここで型推論されたコンストラクターを選択するか、それともコピーコンストラクターを選択するかです。
コードを試してみると、コピーコンストラクターが選択されていることがわかります。例を拡張するには:
Variable var(num); // infering ctor
Variable var2(var); // copy ctor
Variable var3(move(var)); // move ctor
// Variable var4(Variable(num)); // compiler error
提案と標準の新しいバージョンがこれをどのように指定しているかはわかりません。それは私がまだ理解していない新しい標準のビットである「控除ガイド」によって決定されるようです。
var4
控除が違法である理由もわかりません。g ++からのコンパイラエラーは、ステートメントが関数宣言として解析されていることを示しているようです。