- 24の観点における収束の用語の:https://blog.csdn.net/qq_41453285/article/details/104311944
非メンバ関数テンプレートのエラーの例
-
我々はオペレータとなります*()関数は(詳細は見に再び戻って来ることができる)非メンバ関数版として定義され、すべての乗算演算は、操作を介してアクセスできるようにするためには、Rationalクラスに対して、24の観点で述べています。しかし、テンプレートのために、これらのルールは保持しない場合があります
- たとえばみましょうプット合理的と演算子*()関数は、テンプレートとして定義されているコードは次のとおりです。
//下面与条款24都相同,只是改为了模板
template<typename T>
class Rational {
public:
Rational(const T& numerator = 0, const T& denominator = 1);
const T numerator()const;
const T denominator()const;
};
template<typename T>
const Rational<T> operator*(const Rational<T>& lhs, const Rational<T>& rhs)
{
}
- 今、私たちは、次のコードはコンパイルできません書きます。例えば:
Rational<int> oneHalf(1, 2);
//在条款24中,Rational和operator*为非模板,此处代码可编译通过
//此处,Rational和operator*为模板,编译不通过
Rational<int> result = oneHalf * 2;
エラー解析
- このエラーの理由は、「onehalfが* 2」一致する演算子*()関数上に、エラーが発生しました
- 理由:
- それは、INTに演算子*()関数テンプレート、およびタイプTテンプレートの演算子*()関数テンプレートのインスタンスと一致するように、合理的な<整数>の入力onehalfが
- しかし、第2の動作パラメータ、2 INT、演算子*()関数は、テンプレートは、int型Tから推測することができない場合に
- 最終コンパイラはエラーのために、適切な演算子*()関数とリードを見つけることができませんので、
- 非テンプレートオペレータに*()で、演算子*()2は、Rationalオブジェクトとして(合理的な暗黙的な変換は、次に詳細および句24に行くを提供する)暗黙の変換であってもよいです。しかし、テンプレートで、暗黙の型変換は許可されていません
- テンプレート引数決め手を導き出すためにとら
第二に、友人として宣言されたテンプレート関数
- 「」、私たちは間違ったものを使用するテンプレートクラスとテンプレート関数は、1つの解決策は、()*友人合理的なテンプレートクラス(友人)として宣言されたオペレータにあるで
- レッツ・二度変更し、最終的には間違ったコードになって
最初の修正(コンパイラが、間違ったリンク)
- 私たちは、最初の演算子()*合理的なの友人として宣言します。コードは以下の通りであります:
template<typename T> class Rational { public: //友元,函数声明 friend const Rational operator*(const Rational& lhs, const Rational& rhs); }; //函数定义 template<typename T> const Rational<T> operator*(const Rational<T>& lhs, const Rational<T>& rhs); int main() { Rational<int> oneHalf(1, 2); //编译通过,但是链接时出错 Rational<int> result = oneHalf * 2; return 0; }
- 注:生活の中で上の友人、私たちは後ろに合理的な追加しない<T>は、Rational <T>は同じで、両方ともされています
- の理由によってコンパイルされました:
- onehalfがオブジェクトが定義されている場合、プログラムが定義された合理的な<整数>クラスは、クラス合理<整数>を生成します出てインスタンス化されます
- クラス合理<整数>インスタンス化された後、友人演算子*()関数は自動的に宣言されている(注:のみ宣言されていますが定義されていません)
- 友人演算子*()関数が出て宣言された後、関数がのではなく、テンプレート機能である、我々は機能2に渡すことができますので、(2暗黙的およびパラメータの型変換は、Rational 2に変換されます)
- したがって、上記コンパイラによってその上にコードが、リンクエラー(後述)
- エラーリンクの理由:
- インスタンス化されるクラス合理<整数>は友人だけ演算子*()文で、出て来たが、定義されていない、プログラムエラーそうなので
憲法修正第2条(適切なバージョン)
- 上記のコードのコンパイルが、定義は、オペレータを見つけることができなかったことから、経由リンク*()の
- 解決するためのリンクエラー方法は次のとおりです。同時に、声明のフレンド関数で、この関数の定義。コードは以下の通りであります:
template<typename T> class Rational { public: //声明的时候,同时实现该函数(备注,该函数虽然在类中定义,但不属于成员函数) friend const Rational operator*(const Rational& lhs, const Rational& rhs) { return Rational(lhs.numerator()*rhs.numerator(), lhs.denominator()*lhs.denominator()); } };
- ここで友人のもう一つの利点:この機能は、私たちの友人を宣言しますが、そう比較的安全な、非パブリックメンバーのいずれかのクラスにアクセスすることができませんでしたが
第三には、友人のヘルパー関数の呼び出し(インラインに関連する)を作ります
- 私たちは、関数がクラスで定義されている場合30の観点で、インラインになるだろうと述べているので、我々は()のクラスの友人演算子を定義する上で*インラインで呼び出されます
- インラインの影響を最小限にするために我々はできる、もたらします:
- 私たちは、どのようなオペレータに*)(行うことができない別の補助機能への完全なものになるだろう
- ヘルパーはテンプレートでなければなりません
-
コードは以下の通りであります:
-
クラスのオペレータ*()最適化されたインラインを作るために、我々は完全なオペレータ*()関数を完了することになっているヘルパー関数を定義します
-
doMultiply()(例えばオブジェクトとINTのRational乗算など)ハイブリッド動作をサポートしていないが、関数*()(のみオペレータによって呼び出され、オペレータ*される)混合動作をサポートするため、機能的
-
//声明
template<typename T> class Rational
//函数声明(定义在下)
template<typename T>
const Rational<T> doMultiply(const Rational<T>& lhs, const Rational<T>& rhs);
template<typename T>
class Rational {
public:
friend
const Rational operator*(const Rational& lhs, const Rational& rhs)
{
//在其中调用doMultiply(),可使inline最优化
return doMultiply(lhs, rhs);
}
};
//完成原本operator*()要完成的功能
template<typename T>
const Rational<T> doMultiply(const Rational<T>& lhs, const Rational<T>& rhs)
{
return Rational<T>(lhs.numerator()*rhs.numerator(),
lhs.denominator()*lhs.denominator());
}
IVの概要
- 私たちは、クラステンプレートを書き、それが「クラステンプレートのフレンド関数の内部」として定義され、それらの機能を設定する機能がサポートする「暗黙の型変換のすべてのパラメータ」「これに関連したテンプレート」を、提供する場合