Modern C++編【標準ライブラリ】 第7章 array

先頭へ戻る

このエントリーをはてなブックマークに追加

この章の概要

この章の概要です。

概要

std::array は、要素数が固定された配列を表現したクラステンプレートです

std::array を使うには、array という名前の標準ヘッダをインクルードする必要があります。

メンバ変数に、生の配列を保持しているほか、配列操作のために便利な機能を多数備えています。生の配列をそのまま持っているので、各要素がメモリ上に連続的に並ぶことが保証されています。

std::array は動的な確保を行わないので、要素数が固定で構わないのであれば、std::vector(第6章)よりもメモリ使用量や、実行速度の面でも有利になります。余計なメンバ変数もありませんから、通常の配列と同じ性能を維持しているといって良いでしょう。

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

namespace std {
    template <typename T, size_t N>
    struct array {
    };
}

テンプレートパラメータ T は配列の要素の型、N はサイズ(要素数)です。例えば、int型で要素数 100 の配列を、次のようにして得られます。

std::array<int, 100> intArray;

生成と初期化

std::array には、明示的に宣言されたコンストラクタがありません。

std::array は生の配列を保持していますが、実はこれは「公開」されたメンバ変数になっています。例えば以下のように定義されています。

namespace std {
    template <typename T, size_t N>
    struct array {
        T elems[N];  // 名前は実装依存

        // その他、多数のメンバがあるが、
        // コンストラクタは無い。
    };
}

公開されているとはいえ、内部配列の名前は実装依存なので、名前が必要になるような使い方をすべきではありません。


std::array は集成体であるため、リスト初期化が使用できます(【言語解説】第16章)。つまり、配列と同じように、{ } を使って各メンバの初期値を指定する構文が利用できます。

#include <array>

int main()
{
    std::array<int, 5> a = {0, 1, 2, 3, 4};
}

初期化時に「=」を使う、コピー初期化の記法であればこれで問題ありませんが、「=」を使わない直接初期化の記法の場合は、{ } を2組使う必要があります(ただし、C++14 からは改善されています。【言語解説】第16章)。

#include <array>

int main()
{
    std::array<int, 5> a {{0, 1, 2, 3, 4}};  // C++11 では { } が2組必要
}

この2組の {} は、集成体である std::array そのものに与える初期化リストと、メンバ変数の配列に与える初期化リストの2つを表しています。

C++14 で言語仕様が修正されたため、このようなケースでは、1組の { } だけで記述できるようになりました(【言語解説】第16章)。そのため、std::array の初期化は、以下のように記述できます。

std::array<int, 5> a {0, 1, 2, 3, 4};  // C++14 からは { } は1組で良い


明示的なコンストラクタが無いので、コンパイラが自動生成するデフォルトコンストラクタを使えますから、初期値を与えずに生成することもできます。

#include <array>

int main()
{
    std::array<int, 5> a;  // 要素は未初期化
}

この場合は、内部配列は一切初期化されず、不定値が入ったままです。std::array はこの点においては、生の配列と危険性が変わっていないことに注意して下さい。

要素をきちんと初期化するためには、空の { } を与えると良いです。こうすると、各要素はデフォルトの方法で初期化されます。つまり、明示的に定義されたデフォルトコンストラクタがあればそれを呼び、なければ 0 による初期化を試みます。

#include <array>

int main()
{
    std::array<int, 5> a = {};  // 各要素の値は 0
}

破棄

std::array は、終了処理が必要なメンバを持っていないので、デストラクタは何も行いません。

仮想デストラクタ(【言語解説】第36章)ではないので、 std::array の派生クラスを定義して使用することは、不適切な場合があるのので注意して下さい

メンバ型

std::array には、幾つかの型名が「公開」されたメンバとして定義されています。以下、表にまとめて紹介しますが、メンバ型の名前と、その意味だけがポイントとなります。具体的にどう定義されているかは、実装によって異なります。

まず、要素の型に関する定義があります。

メンバ型名 意味
value_type 要素の型。テンプレートパラメータ T のこと。
reference 要素の参照型。T&
const_reference 要素の const参照型。const T&
pointer 要素のポインタ型。T*
const_pointer 要素の constポインタ型。const T*

大きさや距離に関する型があります。

メンバ型名 意味
size_type 主に要素数を意味する型。符号無し整数。
多くの実装で std::size_t と同じ。
difference_type 主に距離を意味する型。符号付き整数。
多くの実装で std::ptrdiff_t と同じ。

イテレータに関する型があります。イテレータについては、「イテレータ」の項で説明しています。

メンバ型名 意味
iterator イテレータ型
const_iterator constイテレータ型
reverse_iterator 逆イテレータ型
const_reverse_iterator const逆イテレータ型

要素のアクセス

要素へアクセスする方法は幾つかあります。ここで取り上げる各メンバ関数([]演算子もメンバ関数です)はそれぞれ、constメンバ関数版と、非メンバ関数版とがあります。

また、std::get関数テンプレートを使う方法がありますが、これは「タプルとしての操作」の項で取り上げます。

[]演算子

std::array は [] を使った添字アクセスが可能です。

#include <array>
#include <iostream>

using IntArray = std::array<int, 5>;

int main()
{
    IntArray a;

    a[3] = 10;
    IntArray::value_type v = a[3];

    std::cout << v << std::endl;
}

実行結果:

10

添字に 0未満の数や、現在の「サイズ」以上の数を指定した場合、範囲外アクセスになってしまいます。これは普通の配列の場合と同じで、何が起こるか分からない危険な操作です。

C++14 (constメンバ関数版の []演算子の constexpr化)

C++14 から、constメンバ関数版の []演算子は、constexpr関数(【言語解説】第24章)になっています。

VisualC++、Xcode ともに対応されています。

C++17 (非constメンバ関数版の []演算子の constexpr関数化)

C++17 から、非constメンバ関数版の []演算子は、constexpr関数(【言語解説】第24章)になっています。

VisualC++ では、対応されています。Xcode は対応していません。

at

範囲外アクセスで未定義の動作になってしまうことを防ぎ、備えが欲しければ、atメンバ関数を使用します。atメンバ関数は、添字を引数に取り、その位置にある要素の参照を返します。[] を使う場合と違うのは、範囲外アクセスになったときに std::out_of_range例外を送出する点です

例外については、【言語解説】第18章で、std::out_of_range については第12章で解説しますが、 ここでは使用例だけ挙げておきます。

#include <array>
#include <iostream>

using IntArray = std::array<int, 5>;

int main()
{
    IntArray a;

    try {
        a.at(3) = 10;
        IntArray::value_type v = a.at(3);
        std::cout << v << std::endl;

        a.at(50) = 10;  // 範囲外アクセス

        // 実行されない
        std::cout << "!!!!!" << std::endl;
    }
    catch (const std::out_of_range& ex) {
        std::cerr << ex.what() << std::endl;
    }
}

実行結果:

10
invalid array<T, N> subscript

実行結果の2行目は、VisualC++ の場合のものです。この部分は、環境によって異なるはずです。

C++14 (constメンバ関数版の atメンバ関数の constexpr化)

C++14 から、constメンバ関数版の atメンバ関数は、constexpr関数(【言語解説】第24章)になっています。

VisualC++、Xcode ともに対応されています。

C++17 (非constメンバ関数版の atメンバ関数の constexpr関数化)

C++17 から、非constメンバ関数版の atメンバ関数は、constexpr関数(【言語解説】第24章)になっています。

VisualC++ では、対応されています。Xcode は対応していません。

front、back

また、std::array の先頭要素(の参照)を frontメンバ関数で、末尾の要素(の参照)を backメンバ関数で取得できます。これらのメンバ関数は、std::array のサイズが 0 の場合には、未定義の動作になることに注意して下さい

#include <array>
#include <iostream>

using IntArray = std::array<int, 5>;

int main()
{
    IntArray a;

    const IntArray::size_type size = a.size();
    for (int i = 0; i < static_cast<int>(size); ++i) {
        a[i] = i;
    }

    std::cout << a.front() << std::endl;
    std::cout << a.back() << std::endl;
}

実行結果:

0
4

C++14 (constメンバ関数版の front、backメンバ関数の constexpr化)

C++14 から、constメンバ関数版の frontメンバ関数、backメンバ関数は、constexpr関数(【言語解説】第24章)になっています。

VisualC++、Xcode ともに対応されています。

C++17 (非constメンバ関数版の front、backメンバ関数の constexpr関数化)

C++17 から、非constメンバ関数版の frontメンバ関数、backメンバ関数は、constexpr関数(【言語解説】第24章)になっています。

VisualC++ では、対応されています。Xcode は対応していません。

data

std::array で管理されている生の配列の先頭アドレスを返す dataメンバ関数もあります。

#include <array>
#include <iostream>

using IntArray = std::array<int, 5>;

namespace {
    void PrintArray(const int* array, std::size_t size)
    {
        for (std::size_t i = 0; i < size; ++i) {
            std::cout << array[i] << std::endl;
        }
    }
}

int main()
{
    IntArray a;

    const IntArray::size_type size = a.size();
    for (int i = 0; i < static_cast<int>(size); ++i) {
        a[i] = i;
    }

    PrintArray(a.data(), a.size());
}

実行結果:

0
1
2
3
4

dataメンバ関数は、非constメンバ関数版と、constメンバ関数版とがあります。前者は std::array<>::pointer型、後者は std::array<>::const_pointer型で返します。

std::array の内部にある配列は、その要素がメモリ上に並んでいることが保証されているので、このサンプルプログラムのように、普通の配列の先頭アドレスが返されたと考えて使用できます。

なお、dataメンバ関数が返したアドレスを p とすると、p ~ p[a.size()-1] の範囲しか安全なアクセスは保証されません。また、std::array のサイズが 0 の場合の結果は未定義です

C++17 (dataメンバ関数の constexpr化)

C++17 から、dataメンバ関数は、constメンバ関数版、非constメンバ関数版を問わず、constexpr関数(【言語解説】第24章)になっています。

VisualC++ では、対応されています。Xcode は対応していません。

代入

std::array は、テンプレート引数が同一であれば、代入演算子を使ってコピー、あるいはムーブができます。

#include <array>
#include <iostream>

using IntArray = std::array<int, 5>;

namespace {
    void PrintArray(const IntArray& a)
    {
        const IntArray::size_type size = a.size();
        for (IntArray::size_type i = 0; i < size; ++i) {
            std::cout << a[i] << "\n";
        }
        std::cout << std::endl;
    }
}

int main()
{
    IntArray a;

    const IntArray::size_type size = a.size();
    for (int i = 0; i < static_cast<int>(size); ++i) {
        a[i] = i;
    }

    IntArray a2;
    a2 = a;  // a のコピー
    PrintArray(a);

    a2 = { 0, 1, 2 };  // 0, 1, 2 の 3つを代入
    PrintArray(a);
}

実行結果:

0
1
2
3
4

0
1
2
3
4

また、ムーブ代入演算子を使うこともできます。

#include <array>
#include <iostream>
#include <memory>

using PtrArray = std::array<std::unique_ptr<int>, 5>;

namespace {
    void PrintArray(const PtrArray& a)
    {
        const PtrArray::size_type size = a.size();
        for (PtrArray::size_type i = 0; i < size; ++i) {
            if (a[i] == nullptr) {
                std::cout << "null" << "\n";
            }
            else {
                std::cout << *(a[i]) << "\n";
            }
        }
        std::cout << std::endl;
    }
}

int main()
{
    PtrArray a1 = {
        std::unique_ptr<int>(new int(5)),
        std::unique_ptr<int>(new int(10)),
        nullptr,
        std::unique_ptr<int>(new int(5)),
        std::unique_ptr<int>(new int(10))
    };
    PtrArray a2;

    a2 = std::move(a1);
    PrintArray(a1);
    PrintArray(a2);
}

実行結果:

null
null
null
null
null

5
10
null
5
10

特定の値で埋める

fillメンバ関数を使うと、すべての要素を特定の値で埋めることができます。

#include <array>
#include <iostream>

using IntArray = std::array<int, 5>;

namespace {
    void PrintArray(const IntArray& a)
    {
        const IntArray::size_type size = a.size();
        for (IntArray::size_type i = 0; i < size; ++i) {
            std::cout << a[i] << "\n";
        }
        std::cout << std::endl;
    }
}

int main()
{
    IntArray a;
    a.fill(7);
    PrintArray(a);
}

実行結果:

7
7
7
7
7

比較

同じテンプレート実引数を持った std::array は、== などの比較演算子を使って比較可能です。

==演算子は、両者の要素を1つ1つ ==演算子を使って比較し、すべてが true であれば true になります。サイズが異なると、テンプレート実引数も異なっていますから、そもそも比較できません。
!=演算子は、==演算子の逆の結果を返します。

<、<=、>、>= の各演算子は、両者の要素を1つずつ同じ演算子を使って比較し、すべてが true であれば true になります。

#include <array>
#include <iostream>

using IntArray = std::array<int, 5>;

namespace {
    void PrintArray(const IntArray& a)
    {
        const IntArray::size_type size = a.size();
        for (IntArray::size_type i = 0; i < size; ++i) {
            std::cout << a[i] << "\n";
        }
        std::cout << std::endl;
    }
}

int main()
{
    IntArray a1 = {0, 1, 2, 3, 4};
    IntArray a2;

    a2 = a1;
    std::cout << (a1 == a2) << "\n"
              << (a1 != a2) << "\n"
              << (a1 <  a2) << "\n"
              << (a1 <= a2) << "\n"
              << (a1 >  a2) << "\n"
              << (a1 >= a2) << std::endl;

    std::cout << "-----" << std::endl;

    a2[3] = 10;
    std::cout << (a1 == a2) << "\n"
              << (a1 != a2) << "\n"
              << (a1 <  a2) << "\n"
              << (a1 <= a2) << "\n"
              << (a1 >  a2) << "\n"
              << (a1 >= a2) << std::endl;
}

実行結果:

1
0
0
1
0
1
-----
0
1
1
1
0
0

交換

swapメンバ関数を使うと、自身の内容を他の std::array の内容と交換できます。両者のテンプレート実引数は同じでなければなりません。

#include <array>
#include <iostream>

using IntArray = std::array<int, 5>;

namespace {
    void PrintArray(const IntArray& a)
    {
        const IntArray::size_type size = a.size();
        for (IntArray::size_type i = 0; i < size; ++i) {
            std::cout << a[i] << "\n";
        }
        std::cout << std::endl;
    }
}

int main()
{
    IntArray a1 = {0, 1, 2, 3, 4};
    IntArray a2 = {7, 7, 7, 7, 7};

    a1.swap(a2);

    PrintArray(a1);
    std::cout << "-----" << std::endl;
    PrintArray(a2);
}

実行結果:

7
7
7
7
7

-----
0
1
2
3
4

以下のように宣言された、メンバ関数ではない swap関数も存在しています。

namespace std {
    template <typename T, size_t N>
    void swap(array<T,N>& lhs, array<T,N>& rhs);
}

C++17 (std::swapメンバ関数の例外仕様)

C++17 からは、例外仕様が追加されて、以下のように宣言されています。

namespace std {
    template <typename T, size_t N>
    void swap(array<T,N>& lhs, array<T,N>& rhs) noexcept(noexcept(lhs.swap(rhs)));
}

VisualC++、Xcode ともに対応されています。

第2章で、std::swap関数を取り上げていますが、その実引数に std::array を指定すると、自動的に、この std::array専用バージョンが使用されます。

非メンバ関数版の swap は「a.swap(b)」のような形で、メンバ関数版の swap を呼びます。非メンバ関数版は、std::array以外の型の交換であっても同じ記述になるので、汎用的に使えます。

サイズに関する関数

サイズ(要素数)に関する関数を取り上げます。

size

std::array の「サイズ」は、sizeメンバ関数で取得できます。

sizeメンバ関数は、constexpr関数(【言語解説】第24章)です。

#include <array>
#include <iostream>

int main()
{
    std::array<int, 10> a1;
    std::cout << a1.size() << std::endl;

    std::array<int, 100> a2;
    std::cout << a2.size() << std::endl;

    std::array<int, 0> a3;
    std::cout << a3.size() << std::endl;
}

実行結果:

10
100
0

std::array のサイズは、テンプレート実引数で指定しており、静的に定まっています。しかし、size関数は普通のメンバ関数なので、std:array のオブジェクトを作らないと呼び出すことができません。

静的にサイズを得たいときは、std::tuple_size関数を使う方法があります。これは、後程取り上げます

empty


サイズが 0 かどうかを知りたいときは、emptyメンバ関数を使用することができます。

emptyメンバ関数は、constexpr関数(【言語解説】第24章)です。

#include <array>
#include <iostream>

int main()
{
    std::array<int, 0> a;
    if (a.empty()) {
        std::cout << "empty" << std::endl;
    }
}

実行結果:

empty

std::array の場合、2つ目のテンプレートパラメータに 0 を指定しない限り、サイズが 0 になる状況は起こり得ません。

max_size

「サイズ」の最大値というものがあり、max_sizeメンバ関数で取得できます。この値が意味するのは、std::array に格納できる要素数の限界です。std::array にとってのそれは、2つ目のテンプレートパラメータに指定した値と同じです。

max_size関数は constexpr関数(【言語解説】第24章)です。

#include <array>
#include <iostream>

int main()
{
    std::array<int, 10> a1;
    std::cout << a1.max_size() << std::endl;

    std::array<int, 100> a2;
    std::cout << a2.max_size() << std::endl;

    std::array<int, 0> a3;
    std::cout << a3.max_size() << std::endl;
}

実行結果:

10
100
0

イテレータ

イテレータという概念に関する詳細は、第9章で改めて取り上げます。

std::array の先頭要素を指すイテレータを beginメンバ関数で、末尾要素の次を指すイテレータを endメンバ関数で取得できます。

クラスに属さない通常関数としての std::begin関数、std::end関数も存在しており、これらを使ってもイテレータを取得できます。詳細は、第9章で取り上げます。

#include <array>
#include <iostream>

using IntArray = std::array<int, 5>;

int main()
{
    const IntArray a = {0, 1, 2, 3, 4};

    const IntArray::iterator itEnd = a.end();
    for (IntArray::iterator it = a.begin(); it != itEnd; ++it) {
        std::cout << *it << "\n";
    }
    std::cout << std::endl;
}

実行結果:

0
1
2
3
4

beginメンバ関数や endメンバ関数で取得できるイテレータの型は、std::array<>::iterator型です。

ポインタに constポインタがあるように、イテレータには constイテレータがあります。意味合いは同じで、constイテレータが指し示している先の要素は、変更することができません。

constイテレータは、cbeginメンバ関数cendメンバ関数を使って取得できます。そのほか、beginメンバ関数や endメンバ関数の constメンバ関数版を使えば、constイテレータが返されます。
これらの関数が返す constイテレータの型は、std::array<>::const_iterator型です。

C++14以降には、クラスに属さない通常関数としての std::cbegin関数、std::cend関数も存在しており、これらを使ってもイテレータを取得できます。詳細は、第9章で取り上げます(std::begin、std::end は C++11 にありますが、std::cbegin、std::cend は C++14 からです)。

#include <array>
#include <iostream>

using IntArray = std::array<int, 5>;

int main()
{
    const IntArray a = {0, 1, 2, 3, 4};

    const IntArray::const_iterator itEnd = a.cend();
    for (IntArray::const_iterator it = a.cbegin(); it != itEnd; ++it) {
        std::cout << *it << "\n";
    }
    std::cout << std::endl;
}

実行結果:

0
1
2
3
4

これらイテレータの型は、std::array内部で定義されているものですが、その正体が何であるかは実装依存です

なお、beginメンバ関数と endメンバ関数を持っていることによって、std::array に対して範囲for文(【言語解説】第3章、および第16章)を使うことができます。

#include <array>
#include <iostream>

using IntArray = std::array<int, 5>;

int main()
{
    const IntArray a = {0, 1, 2, 3, 4};

    for (IntArray::value_type n : a) {
        std::cout << n << "\n";
    }
    std::cout << std::endl;
}

実行結果:

0
1
2
3
4

要素の型はメンバ型の value_type にあるので、これを使えます。

ただし、auto(【言語解説】第20章)を使うのがより簡単で、より一般的です。

C++17 (begin、end、cbegin、cendメンバ関数の constexpr化)

C++17 から、constメンバ関数版の begin、end、cbegin、cendメンバ関数は、constexpr関数(【言語解説】第24章)になっています。

VisualC++ では、対応されています。Xcode は対応していません。

逆イテレータ

要素を、末尾側から先頭へ向かって逆方向に走査する逆イテレータは、rbeginメンバ関数rendメンバ関数で取得できます。
逆イテレータの型は、std::array<>::reverse_iterator型です。

また、const逆イテレータもあり、こちらは、crbeginメンバ関数crendメンバ関数で取得できます。そのほか、rbeginメンバ関数や rendメンバ関数の constメンバ関数版を使えば、constイテレータが返されます。
const逆イテレータの型は、std::array<>::const_reverse_iterator型です。

#include <array>
#include <iostream>

using IntArray = std::array<int, 5>;

int main()
{
    const IntArray a = {0, 1, 2, 3, 4};

    const IntArray::const_reverse_iterator ritEnd = a.crend();
    for (IntArray::const_reverse_iterator rit = a.crbegin(); rit != ritEnd; ++rit) {
        std::cout << *rit << "\n";
    }
    std::cout << std::endl;
}

実行結果:

4
3
2
1
0

C++17 (rbegin、rend、crbegin、crendメンバ関数の constexpr化)

C++17 から、constメンバ関数版の rbegin、rend、crbegin、crendメンバ関数は、constexpr関数(【言語解説】第24章)になっています。

VisualC++ では、対応されています。Xcode は対応していません。

生配列との連携

std::array の内部にある配列のアドレスは、次のようにすれば取得できます。

std::array<int> a = {0, 1, 2};

std::array<int>::pointer p = &a[0];

要素が連続的に並んでいるので、こうして取得したアドレスを使って memcpy関数などの関数を使用できます。ただし、a が空の状態で「a[0]」をすると未定義な動作になってしまうので注意が必要です

あるいは、dataメンバ関数で、内部の配列のアドレスを得られるので、これを使いましょう。

std::array<int> a = {0, 1, 2};

std::array<int>::pointer p = a.data();

ところで、beginメンバ関数を使って、先頭要素のイテレータを取得する方法では代用できないことに注意して下さい。イテレータ(std::array<>::iterator型) の正体は、ポインタでは無い可能性があるからです。もし、イテレータを使いたいのなら、次のように書く必要があります。

std::array<int>::pointer p = &*v.begin();  // *演算子で間接参照後、アドレスを取得

タプルとしての操作

型を問わず、複数の値を扱う構造を、タプル(組)と呼びます。タプルに対する操作の一部は、共通化された方法で行うことができるようになっていますが、これらの操作を std::array に対して適用することもできます。つまり、std::array をタプルとみなして操作することができます。

std::tuple_size

std::tuple_size は、タプルの要素数を得るためのクラステンプレートです。関数ではありません。

テンプレート実引数に std::array を指定し、value という静的メンバ変数(定数)の値を見ると、そこにタプルの要素数が入っています。型は std::size_t型です。

#include <array>
#include <iostream>

using IntArray = std::array<int, 5>;

int main()
{
    const IntArray a = {0, 1, 2, 3, 4};

    std::cout << std::tuple_size<IntArray>::value << std::endl;
}

実行結果:

5

sizeメンバ関数を使う場合と違って、静的に要素数を得られます。

std::tuple_element

std::tuple_element は、タプルの要素の型を得るためのクラステンプレートです。関数ではありません。

1つ目のテンプレート実引数に、何番目の要素の型を得たいのかを指定し、2つ目のテンプレート実引数に std::array を指定します。type という名前の型メンバ (using で定義された型名)があるので、これを見れば、要素の型が得られます。

#include <array>
#include <iostream>

using IntArray = std::array<int, 5>;

int main()
{
    const IntArray a = {0, 1, 2, 3, 4};

    std::tuple_element<2, IntArray>::type n = a[2];
    std::cout << n << std::endl;
}

実行結果:

2

std::get

std::get は、タプルの要素への参照を得るための関数テンプレートです。

テンプレートパラメータは3つありますが、後続の2つは、実引数から自動的に判断できるので、通常は最初の1つだけを明示的に指定します。1つ目のテンプレートパラメータは、何番目の要素かを指定します。
また、仮引数は std::array の左辺値参照(const参照も可)、あるいは右辺値参照です。

C++17 で、const付きの右辺値参照にも対応しました(後述)。

戻り値の型は、基本的には要素の参照型です。実引数に左辺値参照を渡したなら、戻り値も左辺値参照、実引数が右辺値参照なら、戻り値も右辺値参照です。左辺値参照ならば const が付くこともあります。

#include <array>
#include <iostream>

using IntArray = std::array<int, 5>;

int main()
{
    IntArray a = {0, 1, 2, 3, 4};

    std::get<1>(a) = 9;
    std::cout << std::get<1>(a) << std::endl;
}

実行結果:

9

C++14 (std::get の constexpr化)

C++14 から、std::get関数テンプレートは、constexpr関数(【言語解説】第24章)になっています。

VisualC++、Xcode ともに対応されています。

C++17 (std::get の const右辺値参照版の追加)

C++17 から、std::get関数テンプレートに、仮引数と戻り値の型が const右辺値参照のバージョンが追加されました。

VisualC++ では、対応されています。Xcode は対応していません。


練習問題

問題① std::array の各要素の値を標準出力へ出力する関数テンプレートを作成して下さい。要素の型と要素数がどのように指定されていても使用できるように実装して下さい。どのようなフォーマットで出力するかは自由に決めて構いません。

問題② 要素の型が T、要素数が N の std::array を生成して返す関数テンプレートを作成して下さい。なお、実引数には、すべての要素に与える共通の初期値を指定できるようにして下さい。


解答ページはこちら

参考リンク

更新履歴

'2017/12/9 C++11 で、初期化時の {} が2組必要であったのは、直接初期化に限られるようなので、それに合わせて解説とサンプルプログラムを修正。

'2017/11/30 新規作成。



前の章へ

次の章へ

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

Programming Place Plus のトップページへ