啓蒙された 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;
ここで、コメントで指摘したように、新しい形式の推論の有無にかかわらず、正当な宣言になる理由はありません: は型ではありません(テンプレートです)。したがって、のポインターを宣言するのは意味がありません。タイプ。この例を修正する方法の 1 つを次に示します。MyClass *pm
MyClass
MyClass
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 つの異なる型 (Variable と Variable) のコードに同じ型名 (Variable) があります。私の主観的な観点からは、コードの可読性にかなり影響します。
前の例で述べたように、新機能により構文的には型名のように見えますが、Variable
それ自体は型名ではありません。
次に、Pitiş は、適切な推論を許可するコンストラクターが指定されていない場合にどうなるかを尋ねます。答えは、推論はコンストラクター呼び出しによってトリガーされるため、推論は許可されないということです。コンストラクター呼び出しがなければ、推論はありません。
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++ からのコンパイラ エラーは、ステートメントが関数宣言として解析されていることを示しているようです。