potisanのプログラミングメモ

趣味のプログラマーがプログラミング関係で気になったことや調べたことをいつでも忘れられるようにメモするブログです。

C++&STL ワイド文字列の静的配列からstd::vector<std::wstring>を作成する

本文

C++でワイド文字列の静的配列(const wchar_t ...[];)からstd::vector<std::wstring>へ変換するにはstd::vector<std::wstring>のコンストラクタを使用します。引数には静的配列の(変換したい範囲の)最初と最後要素のアドレスを渡します。このコンストラクタはcpprefjpではイテレータ範囲コンストラクタと呼ばれています

生の配列のコード

C++標準ライブラリのstd::sizestd::beginstd::endstd::cbeginstd::cendには生の配列に対する特殊化が用意されています。次のどの方法でも書けます。

#include <string>
#include <vector>

int main()
{
    const wchar_t* a[3]{L"abc", L"def", L"ghi"};

    // constイテレーター
    std::vector<std::wstring> v1(std::cbegin(a), std::cend(a));
    // ポインタ演算
    std::vector<std::wstring> v2(a, a + std::size(a));
    // constイテレーターとポインタ演算
    std::vector<std::wstring> v3(std::cbegin(a), std::cbegin(a) + std::size(a));
    // 非constイテレーター
    std::vector<std::wstring> v4(std::begin(a), std::end(a));
    // 非constイテレーターとポインタ演算
    std::vector<std::wstring> v5(std::begin(a), std::begin(a) + std::size(a));

    return 0;
}

STLコンテナのコード

std::arraysizebeginendcbegincendをメンバー関数として持つため、生の配列と同名の関数で同様に使用できます。std::~を使えば生の配列と同様の記述も可能です。

#include <array>
#include <string>
#include <vector>

int main()
{
    std::array<const wchar_t*, 3> a{ L"abc", L"def", L"ghi" };

    // constイテレーター
    std::vector<std::wstring> v1(a.cbegin(), a.cend());
    // 非constイテレーター
    std::vector<std::wstring> v2(a.begin(), a.end());
    // constイテレーターとポインタ演算
    std::vector<std::wstring> v3(a.cbegin(), a.cbegin() + a.size());
    // ポインタ演算
    std::vector<std::wstring> v4(a.data(), a.data() + a.size());
    // 非constイテレーターとポインタ演算
    std::vector<std::wstring> v5(a.begin(), a.begin() + a.size());

    return 0;
}

解説

std::vector<std::wstring>コンストラクタの内部では、引数として与えた最初の要素から最後の要素に間接演算子*を適用した結果を引数としてstd::wstringのコンストラクタが呼び出されます(MSVCでの動作)。std::wstringconst wchar_t*型から文字列を作成するコンストラクタを持つため、std::vector<std::wstring>は静的配列の要素に対応した文字列を持つコンテナとして初期化されます。

補足

  • 既存のstd::vector<std::wstring>へワイド文字列配列の要素を追加する場合はstd::back_insert_iteratorstd::copyまたはstd::copy_nを使用します。
  • 変換しながら要素を追加する場合は上記のイテレーターとstd::transformが使えたと思います。
  • C++20からはrangeコンセプトを使用できます。

イテレータ範囲コンストラクタのMSVCでの動作

MSVC(Microsoft Visual Studio Community 2019 16.9.0 Preview 2.0)ではイテレータ範囲コンストラクタはイテレーターの種類(タグ)により動作が変わります。