コンテンツにスキップ

C++/標準ライブラリ/utility

出典: フリー教科書『ウィキブックス(Wikibooks)』

導入

[編集]

<utility>ヘッダーの役割と目的についての概要

[編集]

<utility>ヘッダーは、C++標準ライブラリで提供される重要なヘッダーの1つです。このヘッダーは、汎用的なユーティリティ機能を提供し、さまざまなプログラムで利用されます。主な目的は、プログラムの一般的な機能を補助するための便利なツールやクラスを提供することです。

このヘッダーには、以下のような機能やクラスが含まれています:

ペアとタプル
std::pairクラスとstd::tupleクラスは、複数の値をまとめて扱うためのコンテナです。ペアは2つの値を、タプルは任意の数の値を扱うことができます。
比較関数オブジェクト
std::lessstd::greaterなどの比較関数オブジェクトは、要素の比較を行うための関数オブジェクトです。これらの関数オブジェクトは、アルゴリズムやコンテナなどで使用されます。
ポインタ操作
std::addressof()関数やstd::move()関数など、ポインタの操作や移動セマンティクスをサポートする関数が提供されています。
その他のユーティリティ
その他、便利なユーティリティ関数やクラスが含まれています。例えば、std::swap()関数やstd::exchange()関数などがあります。

<utility>ヘッダーは、C++プログラミングにおいてさまざまな場面で使用されます。特に、ペアやタプルを使用して複数の値をまとめて扱う場合や、比較関数オブジェクトをカスタマイズして異なる比較方法を実装する場合などに活用されます。

ペアとタプル

[編集]

std::pairクラスの紹介と使用方法

[編集]

std::pairクラスは、2つの異なる型のオブジェクトをペアとしてまとめるためのテンプレートクラスです。一般的に、2つの値を関連付けたい場合に使用されます。以下は、std::pairクラスの基本的な使用方法です:

#include <utility>
#include <iostream>

auto main() -> int {
    // std::pairの宣言と初期化
    std::pair<int, double> myPair(10, 3.14);

    // 値のアクセス
    std::cout << "First: " << myPair.first << ", Second: " << myPair.second << std::endl;

    return 0;
}

std::make_pair()関数の活用方法

[編集]

std::make_pair()関数は、std::pairオブジェクトを作成するための便利な関数です。この関数は、引数として渡された2つの値からstd::pairオブジェクトを作成し、返します。以下は、std::make_pair()関数の使用例です:

#include <utility>
#include <iostream>

auto main() -> int {
    // std::make_pair()関数の使用
    auto myPair = std::make_pair(10, 3.14);

    // 値のアクセス
    std::cout << "First: " << myPair.first << ", Second: " << myPair.second << std::endl;

    return 0;
}

std::tupleクラスの紹介と使用方法

[編集]

std::tupleクラスは、異なる型の複数の値をタプルとしてまとめるためのテンプレートクラスです。std::pairよりも柔軟性があり、任意の数の要素を持つことができます。以下は、std::tupleクラスの基本的な使用方法です:

#include <tuple>
#include <iostream>

auto main() -> int {
    // std::tupleの宣言と初期化
    std::tuple<int, double, std::string> myTuple(10, 3.14, "Hello");

    // 値のアクセス
    std::cout << "First: " << std::get<0>(myTuple)
              << ", Second: " << std::get<1>(myTuple)
              << ", Third: " << std::get<2>(myTuple) << std::endl;

    return 0;
}

構造化束縛とタプルの組み合わせについての説明

[編集]

構造化束縛(Structured Binding)は、C++17から導入された機能で、タプルの要素を個々の変数に分解することができます。以下は、構造化束縛とタプルの組み合わせの例です:

#include <tuple>
#include <iostream>

auto main() -> int {
    // std::tupleの宣言と初期化
    std::tuple<int, double, std::string> myTuple(10, 3.14, "Hello");

    // 構造化束縛を使用してタプルの要素を分解
    auto [a, b, c] = myTuple;

    // 分解した要素のアクセス
    std::cout << "First: " << a << ", Second: " << b << ", Third: " << c << std::endl;

    return 0;
}

構造化束縛を使用すると、タプルの要素を直接変数に代入できるため、コードがより簡潔で読みやすくなります。

比較

[編集]

std::less、std::greaterなどの比較関数オブジェクトの紹介

[編集]

C++では、比較関数オブジェクトを使用して、要素の比較を行うことができます。std::lessstd::greaterなどの比較関数オブジェクトは、標準ライブラリで提供されています。以下は、これらの比較関数オブジェクトの紹介です:

std::less
std::lessは、2つの要素を比較し、第1引数が第2引数よりも小さい場合にtrueを返します。通常、昇順のソートに使用されます。
std::greater
std::greaterは、2つの要素を比較し、第1引数が第2引数よりも大きい場合にtrueを返します。通常、降順のソートに使用されます。

以下は、比較関数オブジェクトを使用した例です:

#include <functional>
#include <iostream>

auto main() -> int {
    // std::lessの使用例
    std::less<int> lessThan;
    std::cout << "Less than: " << lessThan(5, 10) << std::endl; // Output: 1 (true)

    // std::greaterの使用例
    std::greater<int> greaterThan;
    std::cout << "Greater than: " << greaterThan(5, 10) << std::endl; // Output: 0 (false)

    return 0;
}

比較関数オブジェクトのカスタマイズ方法

[編集]

比較関数オブジェクトは、ユーザーが定義した条件に基づいて要素の比較を行うためにカスタマイズすることができます。以下は、比較関数オブジェクトのカスタマイズ方法の例です:

#include <functional>
#include <iostream>

// カスタム比較関数オブジェクトの定義
struct MyCompare {
    bool operator()(int a, int b) const {
        // 偶数のみを比較対象とする
        return a % 2 == 0 && b % 2 == 0 && a < b;
    }
};

auto main() -> int {
    MyCompare myComp;

    // カスタム比較関数オブジェクトの使用例
    std::cout << "Custom compare: " << myComp(4, 6) << std::endl; // Output: 1 (true)
    std::cout << "Custom compare: " << myComp(5, 6) << std::endl; // Output: 0 (false)

    return 0;
}

この例では、MyCompareという名前のカスタム比較関数オブジェクトを定義し、偶数のみを比較対象としています。operator()関数内で、定義した条件に基づいて比較を行います。

ポインタ操作

[編集]

std::addressof()関数の紹介

[編集]

std::addressof()関数は、与えられたオブジェクトへのポインタを取得するための関数です。この関数は、ポインタを取得する際にアドレス演算子&を使用する場合と比べて、アドレス演算子がオーバーロードされている場合に安全な方法を提供します。以下は、std::addressof()関数の使用例です:

#include <iostream>
#include <memory>

auto main() -> int {
    int value{42};
    int* ptr = std::addressof(value);

    std::cout << "Address of value: " << ptr << std::endl;

    return 0;
}

std::exchange()関数の活用方法

[編集]

std::exchange()関数は、指定された値を新しい値に置き換え、置き換え前の値を返す関数です。この関数は、特にスレッドセーフな値の交換操作に便利です。以下は、std::exchange()関数の使用例です:

#include <iostream>
#include <utility>

auto main() -> int {
    int value{42};
    int newValue = 100;

    int oldValue = std::exchange(value, newValue);

    std::cout << "Old value: " << oldValue << ", New value: " << value << std::endl;

    return 0;
}

std::forward()、std::move()などの移動セマンティクスに関する関数の説明

[編集]

移動セマンティクスは、所有権を移動させるためのC++の概念です。std::forward()関数とstd::move()関数は、移動セマンティクスを実現するための重要な関数です。

std::forward()
フォワードング参照を受け取り、適切な転送を行うための関数です。通常、テンプレート関数内で完全転送(perfect forwarding)を実現するために使用されます。
std::move()
引数を右辺値にキャストし、移動セマンティクスを実現するための関数です。通常、所有権を持っているオブジェクトの値を別のオブジェクトに移動するために使用されます。

以下は、std::forward()関数とstd::move()関数の使用例です:

#include <iostream>
#include <utility>

// フォワードング参照を受け取り、その型に応じて転送を行う関数
template<typename T>
void process(T&& arg) {
    auto newValue = std::forward<T>(arg); // T型に応じて転送を行う
    // newValueの後の処理
}

auto main() -> int {
    int value{42};
    int movedValue = std::move(value); // valueを右辺値にキャストし、所有権をmovedValueに移動

    return 0;
}

これらの関数を使用することで、効率的なポインタ操作や移動セマンティクスを実現することができます。

その他のユーティリティ

[編集]

std::swap()関数の活用方法

[編集]

std::swap()関数は、2つの値を交換するための標準ライブラリ関数です。この関数を使用することで、一時変数を介さずに効率的に値を交換することができます。以下は、std::swap()関数の活用方法の例です:

#include <iostream>
#include <utility>

auto main() -> int {
    int a{10}, b{20};

    std::swap(a, b);

    std::cout << "a: " << a << ", b: " << b << std::endl;

    return 0;
}

std::pairとstd::tupleの分解と組み合わせに関する機能

[編集]

std::pairstd::tupleには、分解と組み合わせを行う便利な機能があります。std::tie()関数を使用すると、std::pairstd::tupleの要素を分解して個々の変数に代入することができます。以下は、std::tie()関数を使用した例です:

#include <iostream>
#include <tuple>

auto main() -> int {
    std::pair<int, double> myPair(10, 3.14);
    int a;
    double b;

    // std::tie()を使用してstd::pairの要素を分解
    std::tie(a, b) = myPair;

    std::cout << "a: " << a << ", b: " << b << std::endl;

    return 0;
}

同様に、std::make_pair()関数やstd::make_tuple()関数を使用して、個々の要素を組み合わせてstd::pairstd::tupleオブジェクトを作成することもできます。

std::declval()関数の紹介と使用方法

[編集]

std::declval()関数は、仮想関数の返り値やメンバ関数の戻り値など、値の生成を意図的に回避するための関数です。主に、SFINAE(Substitution Failure Is Not An Error)のコンテキストで使用されます。以下は、std::declval()関数の使用例です:

#include <iostream>
#include <utility>

struct MyType {
    int getValue() { return 42; }
};

auto main() -> int {
    decltype(std::declval<MyType>().getValue()) value; // MyTypeのgetValue()の返り値の型を取得
    std::cout << "Value: " << value << std::endl; // コンパイル時エラーを回避するために使用

    return 0;
}

std::declval()関数は、テンプレートコード内で一時オブジェクトを作成することなく、型の一部を取得するために使用されます。

演習問題

[編集]
ペアとタプルの使用
与えられた2つの整数をstd::pairでペアとしてまとめ、その要素を取り出して出力するプログラムを作成してください。
比較関数オブジェクトの実装
2つの文字列を比較するカスタム比較関数オブジェクトを定義し、その関数オブジェクトを使用して文字列を比較するプログラムを作成してください。
ポインタ操作の実践
与えられた整数の値を格納した変数に対するポインタを取得し、そのポインタの値を変更して元の変数の値が変化することを確認するプログラムを作成してください。
std::swap()関数の活用
2つの文字列を入力し、std::swap()関数を使用してこれらの文字列を交換するプログラムを作成してください。
std::pairstd::tupleの組み合わせ
与えられた整数をstd::tupleでタプルとしてまとめ、std::pairを使用してタプルの一部を取り出して出力するプログラムを作成してください。
std::declval()関数の利用
任意のクラスに対して、std::declval()関数を使用してそのメンバ関数の戻り値の型を取得し、その型の変数を宣言してください。
移動セマンティクスの実践
与えられた2つのベクトルを交換する関数を実装してください。ただし、交換操作は移動セマンティクスを使用して実現してください。

これらの演習問題を通じて、<utility>ヘッダーの機能を実践的に理解し、その使用方法を習得してください。

参考文献

[編集]
  1. C++ Reference - <utility>: cppreference.com/utility
    <utility>ヘッダーに含まれる関数やクラスの詳細なリファレンスが提供されています。
  2. Bjarne Stroustrup. (2013). "The C++ Programming Language (4th Edition)." Addison-Wesley.
    C++言語の標準ライブラリに関する包括的な解説と、標準ライブラリの使用法が説明されています。
  3. Nicolai M. Josuttis. (2012). "The C++ Standard Library: A Tutorial and Reference (2nd Edition)." Addison-Wesley.
    C++標準ライブラリのチュートリアルとリファレンスとして非常に詳細な書籍です。<utility>ヘッダーを含むさまざまな標準ライブラリの機能が解説されています。
  4. Scott Meyers. (2014). "Effective Modern C++: 42 Specific Ways to Improve Your Use of C++11 and C++14." O'Reilly Media.
    C++11およびC++14で導入された機能に焦点を当てた効果的なC++プログラミングの手法が説明されています。移動セマンティクスなどの機能について詳しく解説されています。
  5. Herb Sutter, Andrei Alexandrescu. (2004). "C++ Coding Standards: 101 Rules, Guidelines, and Best Practices." Addison-Wesley.
    C++コーディングの標準的な手法やベストプラクティスがまとめられた書籍です。効果的なC++プログラミングの手法を学ぶのに役立ちます。

これらの参考文献やリソースを活用することで、C++言語や標準ライブラリに関する深い理解を深めることができます。