当前位置:  开发笔记 > 编程语言 > 正文

如何用索引序列构造一个std :: array?

如何解决《如何用索引序列构造一个std::array?》经验,为你挑选了2个好方法。

如何构造一个std::array索引序列,或一个依赖于顺序索引的lambda?

std::iota并且std::generate看起来很相关,但我不确定如何使用它们来构造一个std::array,而不是将它们应用于已构造的一个(如果数组的元素类型不是默认构造的话,这是不可能的).

我要干的代码类型示例:

#include 

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 ar = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
    std::array ar2 = {C{0, 1.0}, C{1, 1.0}, C{2, 1.0}};
    return 0;
}

Edgar Rokjān.. 14

下一个方法应该适合你:

template
constexpr auto create_array_impl(std::index_sequence) {
    return std::array{ {I...} };
}

template
constexpr auto create_array() {
    return create_array_impl(std::make_index_sequence{});
}

您可以创建一个数组,如:

constexpr auto array = create_array();

wandbox示例

可以修改前面提到的解决方案,以便以下一种方式添加lambda:

template
constexpr auto create_array_impl(F&& func, std::index_sequence) {
    return std::array{ {func(I)...} };
}

template
constexpr auto create_array(F&& func) {
    return create_array_impl(std::forward(func), std::make_index_sequence{});
}

然后使用:

const auto array = create_array([](auto e) {
    return e * e;
});

wandbox示例



1> Edgar Rokjān..:

下一个方法应该适合你:

template
constexpr auto create_array_impl(std::index_sequence) {
    return std::array{ {I...} };
}

template
constexpr auto create_array() {
    return create_array_impl(std::make_index_sequence{});
}

您可以创建一个数组,如:

constexpr auto array = create_array();

wandbox示例

可以修改前面提到的解决方案,以便以下一种方式添加lambda:

template
constexpr auto create_array_impl(F&& func, std::index_sequence) {
    return std::array{ {func(I)...} };
}

template
constexpr auto create_array(F&& func) {
    return create_array_impl(std::forward(func), std::make_index_sequence{});
}

然后使用:

const auto array = create_array([](auto e) {
    return e * e;
});

wandbox示例


@Danra另外,在C++ 17中,它甚至可以用于非可移动类,因为RVO将成为必需,并且不再需要检查移动构造函数是否可用.你正在测试GCC 6.1设置为`-std = gnu ++ 1z`,但是GCC 6还没有实现这个,那就是GCC 7.
@Danra你的课程是不可复制的,也是不可移动的.如果你让它可移动,但保持不可复制,那么它已经有效,需要将`for(auto e:array)`改为`for(auto&e:array)`或`for( auto && e:array)`以防止制作数组元素的副本.

2> ildjarn..:

对于ar,这是一种方法:

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

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

// ...

auto ar = make_iota_array(99);

Online Demo

对于ar2,这是一种方法:

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

template
constexpr auto generate_array(F f) {
  return detail::generate_array(f, std::make_index_sequence{});
}

// ...

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

Online Demo

(noexcept在这里IMO或多或少是可选的,为了简洁起见,这里省略了,但是在演示中存在.)

Nb都是完全的constexpr,但由于generate_array很可能与lambdas一起使用,因此constexpr C++ 17(演示版)之前不会实践.generate_array由于有保证的复制省略(演示),nb 也适用于C++ 17中的不可复制/不可移动类型.


@Danra:请注意,在C++ 17中,由于其新保证的copy-elision,我的答案中的代码_will_ work:[demo](http://melpon.org/wandbox/permlink/xpeIgu9xpEcbazvR).: - ]答案相应更新.
@Danra:由于你的callable将收到一个`integral_constant`而不是`size_t`(假设它使用`auto`),你的callable可以使用常量表达式中的值(例如作为模板参数).
推荐阅读
殉情放开那只小兔子
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有