2016-04-29 4 views
-1

std::vectorのデータからstd::arrayを作成しようとしています。私は現在、この行っている:ベクトルから配列を初期化する方法は? (配列へのポインタのキャスト方法)

#include <vector> 
#include <array> 

int main(void) 
{ 
    std::vector<int> vec{{1, 2, 3, 4, 5}}; 
    std::array<int, 5> arr{static_cast<int [5]>(vec.data())}; 

    (void)arr; 
    return 0; 
} 

をしかし、GCCは、このキャストを受け入れません:

error: invalid static_cast from type ‘int*’ to type ‘int [5]’

私たちは、このキャストを行うことができない理由の配列がそうポインタとして使用することができると思いましたか?

編集:私の質問は約の初期化(建設)のstd::arrayのため、これはCopy std::vector into std::arrayの複製ではありません。コピーしないでください。

編集:私はこの行っている:

#include <vector> 
#include <array> 

int main(void) 
{ 
    std::vector<int> vec{{1, 2, 3, 4, 5}}; 
    int     *a(vec.data()); 
    std::array<int, 5> arr{*reinterpret_cast<int (*)[5]>(&a)}; 

    (void)arr; 
    return 0; 
} 

をしかし、配列が初期化されません... GCCは言う:

error: array must be initialized with a brace-enclosed initializer

+0

この初期化ではどうなるでしょうか?あなたはポインタとサイズを提供し、コンストラクタはそれをコピーしますか?そして、 'int *'を 'int [5]'にキャストできるとはどのように思いますか? – Chiel

+0

@Chiel配列をCのlitteral配列のように初期化します。私はそれをベクトルの 'data()'メソッドから供給します。それが不可能な場合、理由は何ですか? – Boiethios

+0

@HostileFork配列からポインタへのC++のやり方はありますか?配列のアドレスとサイズを知っているので、なぜここではできませんでしたか? – Boiethios

答えて

2

std::arrayは集合型です。ユーザー定義のコンストラクタはありません。単一のデータメンバは配列であり、関数またはコンストラクタ呼び出しで渡すことはできません。値によって渡された配列は最初の要素へのポインタに減衰し、array passed by reference cannot be used to initialize an array data memberです。

これはarray<T, N>のみ別array<T, N>によって、または{} -enclosedリストにおけるタイプTの最大N値のリテラルのシーケンスによって初期化することができることを意味します。 C++ 17から

、あなたはstd::arrayに配列への参照を変換するライブラリ関数to_arrayを使用することができます:あなたはPossible implementationのセクションで見ることができるように、これは内部的に初期化され

std::array<int, 5> arr{std::experimental::to_array(*reinterpret_cast<int (*)[5]>(&a))}; 

個別要素:cpp arrayリファレンスから

return { {a[I]...} }; 
+1

reinterpret_castは悪いことではありませんか?コンパイラの警告によると、「型変換されていない参照ポインタは、厳密なエイリアシング規則を破ります」*。 – HostileFork

+0

@HostileForkはい、残念なことに - http://stackoverflow.com/questions/20046429/casting-pointer-to-array-int-to-int2キャストの結果がaで使用されているので、悪い結果をもたらす可能性は非常に低いです自己完結型の方法ですが、正式には正式な動作ではありません。 – ecatmur

0

The array classes are aggregate types, and thus have no custom constructors.

デフォルトの初期化を使用してそれを構築し、それにベクトルコンテンツをコピーする必要があります。

2

"私は配列としてポインタを使うことができると思ったので、なぜこのキャストはできないのですか?"

配列をポインタとして使用することができます。なぜなら、ポインタは配列に「崩壊する」ためです。 "What is array decaying?"

しかし、逆のことは当てはまりません。

static_cast一部暗黙的な変換を逆転するために使用することができますが、これはちょうどそれらの一つではありません(だけでなく、異なるサイズの配列を上のチェックを入力します。あります)。これは、明示的にexcluded from the listです:

5) If a standard conversion sequence from new_type to the type of expression exists, that does not include lvalue-to-rvalue, array-to-pointer, function-to-pointer, null pointer, null member pointer, function pointer, (since C++17) or boolean conversion, then static_cast can perform the inverse of that implicit conversion.

だから、これはあなたが配列型へのポインタを変換する方法を疑問になるかもしれません。することはできませんので、"Arrays are second-class citizens in C (and thus in C++)."reinterpret_castのいずれかが動作しません。

(あなたがしようと(int [5])(vec.data())などのCスタイルのキャストを使用している場合は、おそらくISO C++が配列型にキャスト禁じより明確なメッセージになるだろう「int型[5]」。)

だからそれはただですどのように言語の実装が落ちるか。本当にただwrap a C arrayすることであり、ここで何をやっていることは、その存在意義std::arrayを初期化しようとしている:

This container is an aggregate type with the same semantics as a struct holding a C-style array T[N] as its only non-static data member.

だから、フォームを初期化するために来るとき、何かをできるようにするつもりはありませんあなたはC配列のためにできませんでした。そしてあなたの手に整数のポインタを持っていて、そのポインタからint arr[5] = ...を初期化したいのであれば、同様に運が悪いです。それをコピーする必要があります。

とで行うことができ、この場合

...

Copy std::vector into std::array

1

あなたが望むものに似た何かを達成するために、再帰的なテンプレートを使用することができます。そのトリックは、変数のパラメータとして必要なベクトル要素インデックスを持つ可変長テンプレートの...演算子を使用して、配列コンストラクタへのパラメータリストを構築することです。これを実現する以下の実装では、配列自体の構築がテンプレート内で行われ、戻り値の最適化を使用して、最後の配列に値を取得するためのコピーが行われないようにすることができます。これは、ベクトルから配列を初期化することを目的としていますが、実際にやりたいとは限りません。

#include <vector> 
#include <array> 
#include <iostream> 

template<typename T, unsigned total_elem_count, unsigned remain_elem_count, unsigned... elements> 
struct init_array_from_vec_helper 
{ 
    static std::array<T, total_elem_count> array_from_vec(const std::vector<T>& cont) 
    { 
     return init_array_from_vec_helper<T, total_elem_count, remain_elem_count-1, remain_elem_count-1, elements...>::array_from_vec(cont); 
    } 
}; 


template<typename T, unsigned total_elem_count, unsigned... elements> 
struct init_array_from_vec_helper<T, total_elem_count, 0, elements...> 
{ 
    static std::array<T, total_elem_count> array_from_vec(const std::vector<T>& cont) 
    { 
     return std::array<T, total_elem_count>{cont[elements]...}; 
    } 
}; 

template<typename T, unsigned total_elem_count> 
std::array<T, total_elem_count> init_array_from_vec(const std::vector<T>& vec) 
{ 
    return init_array_from_vec_helper<int, total_elem_count, total_elem_count-1, total_elem_count-1>::array_from_vec(vec); 
} 

int main(void) 
{ 
    std::vector<int> vec{{1, 2, 3, 4, 5}}; 

    std::array<int, 5> arr(init_array_from_vec<int, 5>(vec)); 

    (void)arr; 

    for(int i : arr) 
     std::cout << i << std::endl; 

    return 0; 
} 
関連する問題