クラステンプレート 解答ページ | Programming Place Plus C++編【言語解説】 第20章

トップページC++編

C++編で扱っている C++ は 2003年に登場した C++03 という、とても古いバージョンのものです。C++ はその後、C++11 -> C++14 -> C++17 -> C++20 -> C++23 と更新されています。
なかでも C++11 での更新は非常に大きなものであり、これから C++ の学習を始めるのなら、C++11 よりも古いバージョンを対象にするべきではありません。特に事情がないなら、新しい C++ を学んでください。 当サイトでは、C++14 をベースにした新C++編を作成中です。

問題①

問題① 標準ライブラリには、比較的単純なクラステンプレートとして std::pair があります。この章で取り上げた Stackクラステンプレートを使い、スタックの要素が std::pair であるようなプログラムを作成してください(std::pair については、【標準ライブラリ】第3章で解説しています)。


// Stack.h

#include <cassert>

template <typename T>
class Stack {
public:
    typedef T value_type;

    explicit Stack(std::size_t capacity);
    ~Stack();

    void Push(const T& data);
    void Pop();
    inline const value_type Top() const
    {
        return mData[mSP - 1];
    }

    inline std::size_t GetSize() const
    {
        return mSP;
    }
    inline std::size_t GetCapacity() const
    {
        return mCapacity;
    }

private:
    const std::size_t      mCapacity;
    T*                     mData;
    int                    mSP;
};

template <typename T>
Stack<T>::Stack(std::size_t capacity) :
    mCapacity(capacity),
    mData(new T[capacity]),
    mSP(0)
{
}

template <typename T>
Stack<T>::~Stack()
{
    delete [] mData;
}

template <typename T>
void Stack<T>::Push(const T& data)
{
    assert(static_cast<std::size_t>(mSP) < mCapacity);
    mData[mSP] = data;
    mSP++;
}

template <typename T>
void Stack<T>::Pop()
{
    assert(mSP > 0);
    mSP--;
}
#include <iostream>
#include <utility>
#include "Stack.h"

int main()
{
    typedef Stack<std::pair<int, int> > PairStack;

    PairStack pStack(10);
    pStack.Push(std::make_pair(0, 90));
    pStack.Push(std::make_pair(1, 75));
    pStack.Push(std::make_pair(2, 85));

    const std::size_t size = pStack.GetSize();
    for (std::size_t i = 0; i < size; ++i) {
        const PairStack::value_type value = pStack.Top();

        std::cout << value.first << ", " << value.second << std::endl;
        pStack.Pop();
    }
}

実行結果:

2, 85
1, 75
0, 90

Stack も std::pair もクラステンプレートであるため、組み合わせて使うと、テンプレート仮引数が入れ子の状態になります。本編でも取り上げたように、>> が連続すると、シフト演算子と解釈してしまうコンパイラもあるので注意してください。

std::pair の使い方が習得できていれば、それほど難しくはないと思いますが、typedef を利用することや、しっかり const を使うことなど、これまでの基礎をよく確認してください。

問題②

問題② 任意の型の3つの値を管理できるクラステンプレートを作ってみてください。値の管理に必要な最低限のメンバがあれば十分です。


template <typename T1, typename T2, typename T3>
class ThreeSome {
public:
    typedef T1 first_type;
    typedef T2 second_type;
    typedef T3 third_type;

    ThreeSome() :
        first(T1()), second(T2()), third(T3())
    {}

    ThreeSome(const T1& first, const T2& second, const T3& third) :
        first(first), second(second), third(third)
    {}


    first_type   first;
    second_type  second;
    third_type   third;
};


template <typename T>
void PrintThreeSome(const T& t)
{
    std::cout << t.first << ", " << t.second << ", " << t.third << std::endl;
}

int main()
{
    typedef ThreeSome<std::string, int, int> DataType1;
    typedef ThreeSome<std::string, bool, double> DataType2;

    DataType1 data1("aaaa", 50, 100);
    DataType2 data2("bbbb", true, 3.5);

    PrintThreeSome(data1);
    PrintThreeSome(data2);
}

実行結果:

aaaa, 50, 100
bbbb, 1, 3.5

std::pair における first、second に続けて third が使えるようになれば良いだけです。

便利なようにも思えますが、メンバ変数へアクセスする際に「first」「second」「third」のような、具体性がない名前になってしまうことが、弱点と言えます。実際のところ、専用のクラスを定義した方が良いと言えるケースが多いと思われます。

【上級】C++11 であれば、3つ以上の任意の数の値をまとめて管理できる std::tuple があるので、この練習問題のようなクラステンプレートを自作するよりは、std::tuple を使った方がいいです。


参考リンク


更新履歴

’2014/10/25 新規作成。



第20章のメインページへ

C++編のトップページへ

Programming Place Plus のトップページへ



はてなブックマーク に保存 Pocket に保存 Facebook でシェア
X で ポストフォロー LINE で送る noteで書く
rss1.0 取得ボタン RSS 管理者情報 プライバシーポリシー
先頭へ戻る