web-dev-qa-db-ja.com

インデックスシーケンスを使用してstd :: arrayを構築する方法は?

インデックスシーケンス、またはシーケンシャルインデックスに依存するラムダを使用してstd::arrayを構築するにはどうすればよいですか?

std::iotastd::generateは関連しているようですが、それらを使用してstd::arrayを構築する方法がわかりません。むしろ、すでに構築されているものに適用します(これはで不可能です)。配列の要素タイプがデフォルトでは構築できない場合)。

私が乾燥させたい種類のコードの:

#include <array>

class C
{
public:
    C(int x, float f) : m_x{x}, m_f{f} {}
private:
    int m_x;
    float m_f;
};

int main()
{
    std::array<int, 10> ar = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
    std::array<C, 3> ar2 = {C{0, 1.0}, C{1, 1.0}, C{2, 1.0}};
    return 0;
}
21
Danra

arの場合、次のアプローチがあります。

namespace detail {
  template<typename T, T... Ns>
  constexpr auto make_iota_array(T const offset, std::integer_sequence<T, Ns...>) noexcept
   -> std::array<T, sizeof...(Ns)> {
    return {{(Ns + offset)...}};
  }
}

template<typename T, T N>
constexpr auto make_iota_array(T const offset = {}) noexcept {
  static_assert(N >= T{}, "no negative sizes");
  return detail::make_iota_array<T>(offset, std::make_integer_sequence<T, N>{});
}

// ...

auto ar = make_iota_array<int, 10>(99);

Online Demo

ために ar2、ここにアプローチがあります:

namespace detail {
  template<typename T, typename F, std::size_t... Is>
  constexpr auto generate_array(F& f, std::index_sequence<Is...>)
   -> std::array<T, sizeof...(Is)> {
    return {{f(std::integral_constant<std::size_t, Is>{})...}};
  }
}

template<typename T, std::size_t N, typename F>
constexpr auto generate_array(F f) {
  return detail::generate_array<T>(f, std::make_index_sequence<N>{});
}

// ...

auto ar2 = generate_array<C, 3>([](auto i) -> C { return {i, i * 1.12f}; });

Online Demo

noexceptは、ここでは多かれ少なかれオプションであり、簡潔にするためにここでは省略されていますが、デモには存在します。)

N.b.どちらも完全にconstexprですが、generate_arrayはラムダで使用される可能性が高く、C++ 17( demo )まで実際にはconstexprではありません。また、n.b。 generate_arrayは、 コピーの省略が保証されているデモ )のため、C++ 17のコピー不可/移動不可のタイプで機能します。

13
ildjarn

次のアプローチはあなたのために働くはずです:

template<typename T, std::size_t N, std::size_t... I>
constexpr auto create_array_impl(std::index_sequence<I...>) {
    return std::array<T, N>{ {I...} };
}

template<typename T, std::size_t N>
constexpr auto create_array() {
    return create_array_impl<T, N>(std::make_index_sequence<N>{});
}

次のような配列を作成できます。

constexpr auto array = create_array<std::size_t, 4>();

wandboxの例

前述のソリューションを変更して、次の方法でラムダを追加できます。

template<typename T, std::size_t N, typename F, std::size_t... I>
constexpr auto create_array_impl(F&& func, std::index_sequence<I...>) {
    return std::array<T, N>{ {func(I)...} };
}

template<typename T, std::size_t N, typename F>
constexpr auto create_array(F&& func) {
    return create_array_impl<T, N>(std::forward<F>(func), std::make_index_sequence<N>{});
}

そして、使用します:

const auto array = create_array<std::size_t, 4>([](auto e) {
    return e * e;
});

wandboxの例

14
Edgar Rokjān