効果的なC ++項目46:テンプレートとジェネリックプログラミングの(型変換を必要なときに非テンプレートメンバ関数を定義してください)

非メンバ関数テンプレートのエラーの例

  • 我々はオペレータとなります*()関数は(詳細は見に再び戻って来ることができる)非メンバ関数版として定義され、すべての乗算演算は、操作を介してアクセスできるようにするためには、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の概要

  • 私たちは、クラステンプレートを書き、それが「クラステンプレートのフレンド関数の内部」として定義され、それらの機能を設定する機能がサポートする「暗黙の型変換のすべてのパラメータ」「これに関連したテンプレート」を、提供する場合
リリース1525元の記事 ウォンの賞賛1084 ビュー45万+

おすすめ

転載: blog.csdn.net/qq_41453285/article/details/104887321