第35章 冶金工場5

 今回はテンプレートの強力さを見てみます。前回の終わりのヒントを元に試してみた人も改めて見ておいて下さい。


 それでは、今回の要点です。


 では、いってみましょう。


 先ず最初に、関数テンプレート Max をもう一度見てみましょう。

// 大きい方の値を返す関数
template <typename TYPE>
TYPE Max(TYPE a, TYPE b)
{
    return (a > b) ? a : b;
}

 a と b とを比較し、大きな方を返すという処理を行っています。

 ここで比較には > という演算子を使っています。ということは、> 演算子をオーバーロードしていたらクラスでも Max が使えるのではないでしょうか?

 それではやってみましょう。

プログラム
// Temp4.cpp
#include <iostream.h>
#include <string.h>

class CStr
{
private:
    char m_str[128];

public:
    CStr(const char* str)
    {
        // strncpy はバッファサイズを考慮する
        // 文字列コピー関数です
        // バッファサイズを越えるものをコピーするときは、
        // 最後にヌルターミネータは付きません
        strncpy(m_str, str, sizeof m_str);
        m_str[(sizeof m_str) - 1] = 0;
    }
    const char* Get(){ return m_str; }
    bool operator > (CStr& rother)
    {
        return strcmp(m_str, rother.m_str) > 0;
    }
};

template <typename TYPE>
TYPE Max(TYPE a, TYPE b)
{
    return (a > b) ? a : b;
}

int main()
{
    CStr str1("Would you like to program?"),
         str2("Would you love to program?");

    cout << Max(str1, str2).Get() << endl;

    return 0;
}
実行結果
Would you love to program?

 何と、クラスのオブジェクトにも Max が使えてしまいました。

 このように、> 演算子さえ使えれば Max 関数は使えるのです。

 では、operator > 関数を削除してみましょう。> 演算子が使えなければどうなるのでしょうか?

Temp4.cpp(26) : 二項演算子 '>' :
        'class CStr' は、この演算子または定義済の演算子に適切な型への変換の定義を行いません。
Temp4.cpp(34) : 'class CStr Max(class CStr,class CStr)' の参照を確認してください

 コンパイルエラーになりました。

 つまり、> 演算子が使えなければ実体化ができなくなるのです。

 これらのことは別に演算子に限ったことではなく、メンバなどにも適用できます。つまり、a.Disp(); としておけば、Disp というメンバ関数を持っていればテンプレートは実体化でき、持っていなければ実体化できないということです。


 クラスも渡せるということは、値渡しでなく参照渡しにしたいですね。しかし、上のコンパイルエラーの中にもあるように、そのままでは値渡しになってしまいます。

 そういう場合は戻り値、引数の型を TYPE& にしてしまえばいいのです。

// 大きい方の値を返す関数(参照渡し)
template <typename TYPE>
TYPE& MaxR(TYPE& a, TYPE& b)
{
    return (a > b) ? a : b;
}

 ここで注意することはテンプレート引数の所には & を付けないということです。typename の次には名前だけしか書けません。


 もう1つ「即値を渡してもいいのか?」という疑問があると思います。MaxR(i, 10) のように使っても大丈夫なのか、ということです。

 答を言ってしまうと、「大丈夫」です。即値は一時的に const 変数が作られ、その参照が渡されるという仕組みになります。つまり、上の例では TYPE は const int になり、結局 const int& による比較が行われます。そして、この一時的な変数の寿命は MaxR を呼んだ文のセミコロンの所までです。参照が返ってくるからといって、そのアドレスを保持するようなことはできません。

 最終的に、Max, MaxR 関数はサイズが大したことないということでインライン関数にして、こういう感じにするといいでしょう。

// 大きい方の値を返す関数(値渡し)
template <typename TYPE>
inline TYPE Max(TYPE a, TYPE b)
{
    return (a > b) ? a : b;
}

// 大きい方の値を返す関数(参照渡し)
template <typename TYPE>
inline TYPE& MaxR(TYPE& a, TYPE& b)
{
    return (a > b) ? a : b;
}

 inline は template の後、戻り値の型の前に書きます。これで Max, MaxR 関数の完成です。


 では、今章のことをまとめてみましょう。


 今回で Max 関数は終わりと思いきや、まだ1回続きます。それでは、次回まで。


第34章 冶金工場4 | 第36章 特注の鋳型

Last update was done on 2000.12.6

この講座の著作権はロベールが保有しています