4

これが私が理解していないコードです

#include<iostream>

using namespace std;

template <typename T> 
T calc(T, T) { cout << "template calc" << endl; }

double calc(double, double) { cout << "ordinary calc" << endl; }

template <> 
char calc<char>(char, char) { cout << "template specialisation calc" << endl; }

int main() {

   int ival;
   double dval;
   float fd;

   calc(0, ival); // calls the generic calc(T, T)

   // the following all call calc(double, double)
   calc(0.25, dval);
   calc(0, fd);
   calc(0, 'J');

   calc('I', 'J'); // calls calc(char, char)
}

calcへの関数呼び出しは5つあるので、それらの位置に応じて1)-5)と呼びます。

1)ある種の意味があります。0は整数、ivalは整数、calc(T、T)が呼び出されることは理にかなっています。また、これについての私の推論は間違っているように感じます。結局のところ、これらは両方ともdoubleであるため、calc(double、double)が呼び出された場合、それも意味があります。だからここで説明を探しています。

2)ドラマはありません。どちらもダブルです。calc(double、double)を呼び出します。単純。

3)fdはフロートです。calc(T、T)またはcalc(double、double)のいずれかを呼び出すことができます。1)はcalc(T、T)の呼び出しになっているので、ここでも同じことが当てはまると思います。これも1つのパラメーターが0であるためですが、これはcalc(double、double)を呼び出します。だからこれは私を混乱させます、特にこれと1)の違い

4)最初に考えたのは、0は有効な文字であり、「J」も有効な文字であるため、calc(char、char)を呼び出します。一般的なタイプの整数を使用してcalc(T、T)を呼び出す場合があります。しかし、いや、どちらも間違っています。calc(double、double)を呼び出します。私はこれについて非常に混乱しています。私には意味がありません。

5)は理にかなっていますが、4)で行ったのと同じロジックを適用した場合にのみ、4)で間違っていたため、テンプレートを使用する別の例を見ると、どのロジックを適用するかわかりません。

それで、なぜこのプログラムがそれがすることをするのかについての説明を探しています。

ありがとう。

4

2 に答える 2

1

オーバーロードの解決について読むことをお勧めします:

最も適切なオーバーロードされた関数または演算子を選択するプロセスは、オーバーロードの解決と呼ばれます。

f がオー​​バーロードされた関数名であるとします。オーバーロードされた関数 f() を呼び出すと、コンパイラは一連の候補関数を作成します。この一連の関数には、f() を呼び出したポイントからアクセスできる f という名前の関数がすべて含まれています。コンパイラは、オーバーロードの解決を容易にするために、f という名前のアクセス可能な関数の 1 つの代替表現を候補関数として含めることができます。

候補関数のセットを作成した後、コンパイラは実行可能な関数のセットを作成します。この一連の関数は、候補関数のサブセットです。実行可能な各関数のパラメーターの数は、f() の呼び出しに使用した引数の数と一致します。

コンパイラは、実行可能な関数のセットから、最適な実行可能な関数 (f() を呼び出すときに C++ ランタイム環境が使用する関数宣言) を選択します。コンパイラは、暗黙的な変換シーケンスによってこれを行います。暗黙的な変換シーケンスは、関数呼び出しの引数を関数宣言の対応するパラメーターの型に変換するために必要な変換のシーケンスです。暗黙の変換シーケンスはランク付けされます。一部の暗黙的な変換シーケンスは、他のものよりも優れています。最良の実行可能な関数は、すべてのパラメーターが、他のすべての実行可能な関数よりも優れた、または同等のランクの暗黙的な変換シーケンスを持つ関数です。コンパイラは、コンパイラが実行可能な最適な関数を複数見つけることができたプログラムを許可しません。

1、2、および 5 はすべて完全一致であるため、変換は必要ありません。

3 と 4 を説明するには、関数を削除するとプログラムがコンパイルされないことに注意してくださいdouble, double。これは、3 と 4 のテンプレート引数を推測できないためです (引数の型が一致しないため)。このため、関数のみがdouble, double候補関数と見なされます。

于 2012-11-03T08:37:52.557 に答える
1

まず、ソースコードにリテラルの「0」を書くと、それは「int」型になります。また、呼び出す関数を探す際に、コンパイラは最も一致するものを選択します。利用できない場合、コンパイラは暗黙的な型変換を行って動作させます。

1) 0 と ival の両方が int です

2) double と double の場合、calc(double, double) は正確に一致します

3) int と float の場合、一致するものが見つからないため、両方とも double に変換されます

4) int と char の場合は 3) と同じ

5) char と char の場合、calc(char, char) は正確に一致します

于 2012-11-03T08:32:39.803 に答える