25

私は遊んでいてauto、ほとんどの場合、変数定義を置き換えてautoから型を割り当てることができることに気付きました。

次のコードではw、 とxは同等です (デフォルトでは初期化intされていますが、潜在的なコピーには入りません)。zと同じ型を持つように宣言する方法はありyますか?

int w{};
auto x = int{};
int y[5];
auto z = int[5];
4

5 に答える 5

36

TL;DR

template<typename T, int N> using raw_array = T[N];

auto &&z = raw_array<int,5>{};

型が有効な初期化子ではないという理由だけで、あなたの例はauto z = int[5];これ以上合法ではありません。auto z = int;次のように書くことができauto z = int{};ますint{}

これに気づいたら、次の試みは次のようになります。

auto z = int[5]{};

int y[5]あなたには初期化子がないことに注意してください。もしそうなら、あなたはここにまっすぐジャンプしたでしょう。

残念ながら、これはあいまいな構文の理由で機能しません。代わりに、初期化子で配列型に名前を付ける正当な方法を見つける必要があります。たとえば、typedef 名は初期化子で使用できます。便利な再利用可能なテンプレート型エイリアスにより、配列型ごとに新しい typedef を作成するという面倒な要件がなくなります。

template<typename T, int N> using raw_array = T[N];

auto z = raw_array<int,5>{};

余談: テンプレート型エイリアスを使用して、C++ の奇妙な「インサイドアウト」構文を修正し、この提案を使用して、左から右への規則正しい方法で任意の複合型に名前を付けることができます。


残念ながら、C および C++ の設計上のバグにより、ハットのドロップ時に配列からポインターへの変換が発生するため、推定される変数の型zint*むしろint[5]. 一時配列が破棄されると、結果の変数はダングリング ポインターになります。

C++14 ではdecltype(auto)、さまざまな型推定規則を使用して、配列型を正しく推定します。

decltype(auto) z = raw_array<int,5>{};

しかし今、配列に関する別の設計上のバグに遭遇しました。それらは適切なオブジェクトとして動作しません。配列では、代入、構成のコピー、値渡しなどはできません。上記のコードは、次のように言っています。

int g[5] = {};
int h[5] = g;

本来ならこれでうまくいくはずですが、残念ながら組み込み配列は C と C++ で奇妙な動作をします。私たちの場合、特定の問題は、配列がどのような種類の初期化子を持つことも許可されていないことです。初期化子リストの使用に厳密に制限されています。初期化子リストによって初期化された一時配列は、それ自体は初期化子リストではありません。


答え 1:

この時点で Johannes Schaub は、一時的な有効期間の延長を使用できるという素晴らしい提案をしています。

auto &&z = raw_array<int,5>{};

decltype(auto)を追加すると推定される型が変更されるため、必要ありません&&。そのため、Johannes Schaub の提案は C++11 で機能します。これにより、配列ではなく参照を初期化するため、配列初期化子の制限も回避されます。

配列の長さを初期化子から推測する場合は、不完全な配列型を使用できます。

template<typename T> using unsized_raw_array = T[];

auto &&z = unsized_raw_array<int>{1, 2, 3};

上記はあなたが望むことを行いますが、生の配列は適切な C++ オブジェクトのように動作しないという事実、およびそれらの動作と上記で使用された手法のあいまいさのために、生の配列を完全に避けることを好むかもしれません。

答え 2:

C++11のstd::arrayテンプレートは、代入、値による受け渡しなどを含む適切なオブジェクトのように動作し、組み込み配列がそうでない場合でも、一般的に正常かつ一貫して動作します。

auto z = std::array<int,5>{};

ただし、これを使用すると、配列型が初期化子から独自の長さを推測できるようになることを逃してしまいます。代わりにmake_array、推論を行うテンプレート関数を作成できます。これは、私がテストしていない非常に単純なバージョンであり、すべての引数が同じ型であることを確認したり、型を明示的に指定したりするなど、必要なことを実行しません。

template<typename... T>
std::array<typename std::common_type<T...>::type, sizeof...(T)>
make_array(T &&...t) {
    return {std::forward<T>(t)...};
}

auto z = make_array(1,2,3,4,5);
于 2013-06-05T21:46:37.880 に答える
9

まったく同じではありませんが、次を使用できますarray

auto z = std::array<int, 5>();
于 2013-06-05T20:22:46.220 に答える