web-dev-qa-db-ja.com

サイズを直接指定せずに初期化リストを使用してstd :: arrayを作成する方法

どうすればa3コンパイルしますか?

int main()
{
    int a1[] = { 1, 2, 3 };
    std::array<int, 3> a2 = { 1, 2, 3 };
    std::array<int> a3 = { 1, 2, 3 };
}

初期化リスト、特に長いリストを使用する場合、配列のサイズをハードコーディングするのは非常に不便で、脆弱です。回避策はありますか?そうでなければ、Cの配列とstd::arrayは、代替となるはずです。

39
Neil Kirk

現在のところ、独自のmake_array、これについての提案があります N3824:make_array 次のスコープがあります:

LWG 851は、代替構文を提供することを目的としています

array<T, N> a = { E1, E2, ... };

、したがって、次の

auto a = make_array(42u, 3.14);

整形式です(内部に追加のstatic_castsが適用されています)

array<double, 2> = { 42u, 3.14 };

整形式です。

このペーパーでは、タプルの観点とアレイの観点の両方から包括的なstd :: array作成インターフェイスのセットを提供することを目的としているため、ナローイングは当然禁止されています。設計の決定で、この方向に基づいた詳細を参照してください。

また、 サンプル実装 も含まれます。これはかなり長いため、ここでコピーすることは実用的ではありませんが、Konrad Rudolphには上記のサンプル実装と一致する簡易バージョン here があります。

template <typename... T>
constexpr auto make_array(T&&... values) ->
    std::array<
       typename std::decay<
           typename std::common_type<T...>::type>::type,
       sizeof...(T)> {
    return std::array<
        typename std::decay<
            typename std::common_type<T...>::type>::type,
        sizeof...(T)>{std::forward<T>(values)...};
}
23
Shafik Yaghmour

「このような恐ろしく複雑な(私にとって)機能が必要です」と言うとき、あなたは少し過激になります。自分で簡易バージョンを作成できます。提案には、C配列を変換し、最初のパラメーターから型を推定する「to_array」関数も含まれています。それを省くと、かなり管理しやすくなります。

template<typename T, typename... N>
auto my_make_array(N&&... args) -> std::array<T,sizeof...(args)>
{
    return {std::forward<N>(args)...};
}

あなたはその後、のように呼び出すことができます

auto arr = my_make_array<int>(1,2,3,4,5);

編集:私が見落とした提案には実際にそのバージョンがあることに言及する必要があるので、これは私のバージョンよりも正しいはずです:

template <typename V, typename... T>
constexpr auto array_of(T&&... t)
    -> std::array < V, sizeof...(T) >
{
    return {{ std::forward<T>(t)... }};
}
12
PeterT