ユーティリティ | Programming Place Plus C++編【標準ライブラリ】 第15章

トップページC++編

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

この章の概要

この章の概要です。


ユーティリティ

この章では、標準ライブラリに含まれている、比較的小粒な便利機能(ユーティリティ)をまとめて紹介します。互いに関係性がない機能は、使用するために必要な標準ヘッダもそれぞれ異なっています。

type_info

std::type_info は、型に関する情報をまとめたクラスです。type_info は、<typeinfo> という標準ヘッダで定義されており、std名前空間に属しています。

このクラスのインスタンスは通常の方法では作れません。typeid演算子を使って const参照を受け取って使用します。typeid演算子についての詳細は、【言語解説】第31章で解説しているので、そちらをご覧ください。本章では、簡単に type_infoクラスの機能を紹介します。

nameメンバ関数

nameメンバ関数は、型の名前を表現する文字列を返します。

const char* name() const;

返される文字列が具体的にどのように表現されているかは、コンパイラの実装依存です。そのため、あるコンパイラで確認した結果が、他のコンパイラでの結果と一致する保証はないので、表現に依存するプログラムを書いてはいけません。

beforeメンバ関数

beforeメンバ関数は、2つの type_info を比べて、順位を決定します。

bool before(const type_info& rhs);

*this の方が、rhs より先に来るのなら true を、後に来るのなら false を返します。この関数における順位とは、実装依存であり、内部的な取り決めに過ぎません。仮に、2つの type_info が表現している型が、継承関係にあったとしても、基底クラスの側が先であるだとかというルールはありません

使う機会は少ないかもしれませんが、この関数があることで、複数の type_info をソートできます。これは、map(第9章)のようなコンテナを使った管理に利用できます。

==演算子、!=演算子

2つの type_info を比べて、同じ型の情報であるかどうかを ==演算子で知ることができます。!=演算子ならその逆で、一致していないことを調べます。

コピー

type_info のコピーは禁止されています。


限界値

C言語には、INT_MAXINT_MIN のように、型ごとに表現できる最大値や最小値を表したマクロが用意されています(C言語編第19章)。これらのマクロは C++ でも使用できますが、できればマクロは避けたいところです。

そこで代わりに、std::numeric_limits というクラステンプレート(【言語解説】第20章)を使用します。使用するには、<limits> という標準ヘッダのインクルードが必要です。

numeric_limits は、次のように定義されています。

namespace std {
    template <typename T> class numeric_limits;

    template <> class numeric_limits<int>;
    template <> class numeric_limits<short>;
    template <> class numeric_limits<unsigned int>;
    template <> class numeric_limits<unsigned short>;
    template <> class numeric_limits<float>;
    template <> class numeric_limits<bool>;

    // その他多数
}

このように、クラステンプレートの特殊化(【言語解説】第23章)を活用して実装されています。上では省略しましたが、C++ で定義されている標準の算術型はすべてあります。このような仕組みで実装されているので、ユーザが自分で作った型に適合する numeric_limits を追加することも可能です。

肝心のメンバですが、こちらも大量にありますが、ここでは最小値と最大値に絞って紹介します。最小値は minメンバ関数を、最大値は maxメンバ関数を使用します。なお、すべてのメンバが静的になっているので、インスタンス化する必要はありません

#include <iostream>
#include <limits>

int main()
{
    std::cout << std::numeric_limits<int>::min() << "\n"
              << std::numeric_limits<int>::max() << std::endl;
}

実行結果

-2147483648
2147483647

swap

std::swap関数は、2つの値を交換します。swap関数を使うには、<algorithm> という標準ヘッダをインクルードする必要があります。

使用例を挙げます。

#include <iostream>
#include <algorithm>

int main()
{
    int a = 10;
    int b = 5;

    std::swap(a, b);
    std::cout << a << ", " << b << std::endl;
}

実行結果

5, 10

swap関数は、関数テンプレートになっているので、型を問わずに使用できます。さらに、標準ライブラリあるいくつかの型に対しては、特殊化(【言語解説】第23章)された関数が用意されており、より効率的な交換処理が行われるようになっています。たとえば、std::swap関数のテンプレート実引数が、vector等の STLコンテナ の場合、メンバ関数版の swap(第4章)を呼び出すコードが実行されます。

なお、2つの引数はともにテンプレート仮引数T の参照なので、異なる型にはできません。

交換処理の実装の都合上、交換する要素が、コピーコンストラクタと代入演算子を使用できなければなりません

swap_ranges

std::swap_ranges関数は、ある2つの範囲内にある要素同士をまとめて交換します。swap_range関数を使用するには、<algorithm> という標準ヘッダをインクルードする必要があります。

#include <iostream>
#include <algorithm>

namespace {

    template <typename T, std::size_t N>
    void print_array(const T(&array)[N])
    {
        for (std::size_t i = 0; i < N; ++i) {
            if (i > 0) {
                std::cout << ", ";
            }
            std::cout << array[i];
        }
        std::cout << std::endl;
    }

}

int main()
{
    int a[] = { 0, 1, 2, 3, 4 };
    int b[] = { 5, 5, 5, 5, 5 };

    std::swap_ranges(a, a + 3, b);

    print_array(a);
    print_array(b);
}

実行結果

5, 5, 5, 3, 4
0, 1, 2, 5, 5

第1引数に範囲の始点を、第2引数に終点(の1つ後ろ)を指定します。第3引数には、もう1つの範囲の始点を指定します。第1、2引数から要素数が判断できるので、2つ目の範囲の終点は指定しません。なお、引数はすべて、前方イテレータ(第14章)です。

iter_swap

std::iter_swap関数は、2つのイテレータが指す要素同士を交換します。この関数については、第14章で解説しているので、そちらを参照してください。


練習問題

問題① コピー操作の可否によって、std::swap関数の使用の可否が変化することを確認してください。

問題② ある型の最小値と最大値のペアを作って返す関数テンプレートを作成してください。


解答ページはこちら

参考リンク


更新履歴

’2018/1/5 コンパイラの対応状況について、対応している場合は明記しない方針にした。

’2017/8/24 swap関数の「C++11 (要件の変更)」を削除。
ムーブができない型でも使えないわけではなく、コピーで動作する。

’2017/7/30 clang 3.7 (Xcode 7.3) を、Xcode 8.3.3 に置き換え。

’2017/3/25 VisualC++ 2017 に対応。

’2016/10/15 clang の対応バージョンを 3.7 に更新。

’2016/5/8 新規作成。



前の章へ (第14章 イテレータ)

次の章へ (第16章 auto_ptr)

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

Programming Place Plus のトップページへ



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