c++ 我如何构造一个std::数组来填充一些统一的值?

8yoxcaq7  于 2023-02-06  发布在  其他
关注(0)|答案(2)|浏览(134)

std::array可以用特定的值构造(在编译时用较新的C++版本),例如

std::array a{1, 4, 9};

然而,它没有构造函数,或者标准库命名的构造函数习惯用法,取单个值并复制它。也就是说,我们没有:

std::array<int, 3> a{11};
// a == std::array<int, 3>{11, 11, 11};

因此,我们如何构造一个只给出了要重复的值的数组呢?

**编辑:**我正在寻找一个解决方案,这将工作,甚至为元素类型是不可默认构造的;因此,经过默认设置的解决方案-构造数组,然后填充它,并不是我所追求的-尽管事实上这将适用于int的情况(如示例中所示)。

4ngedf3f

4ngedf3f1#

我们可以编写一个合适的命名构造函数来实现这一点。然后,你的示例定义如下所示:

auto a = array_repeat<3>(11);
// a == std::array<int, 3>{11, 11, 11};

然而,这个实现有点笨拙,因为我们需要使用"indices trick",而"indices trick"在C11中需要大量的样板文件,所以让我们假设C14:

namespace detail {

template<size_t, class T>
constexpr T&& identity(T&& x) { return std::forward<T>(x); }

template<class T, size_t... Indices>
constexpr auto array_repeat_impl(T&& x, std::index_sequence<Indices...>)
{
    return std::experimental::make_array(identity<Indices>(x)...);
}

} // end detail

template<size_t N, class T>
constexpr auto array_repeat(T&& x)
{
    return detail::array_repeat_impl(std::forward<T>(x), std::make_index_sequence<N>());
}

GodBolt上可以看到这一点。
如果你能用C++20编译你的代码,你可以去掉对make_array的依赖并写上:

namespace detail {

template<size_t, class T>
constexpr T&& identity(T&& x) { return std::forward<T>(x); }

template<class T, size_t... Indices>
constexpr auto array_repeat_impl(T&& x, std::index_sequence<Indices...>)
{
    return std::array{identity<Indices>(x)...};
}

} // end detail

template<size_t N, class T>
constexpr auto array_repeat(T&& x)
{
    return detail::array_repeat_impl(std::forward<T>(x), std::make_index_sequence<N>());
}

GodBolt
注:

  • 这个解决方案有点类似于Jared Hoberock的tuple_repeat,它是tuple utilities for C++11的一部分。
  • 感谢@Caleth和@L.F.指出array_repeat_impl中的不适当转发。
  • array_repert()函数接受右值引用并从中移动,所以在参数中创建一个临时变量是可以的,即使代价很高。
o75abkj4

o75abkj42#

在C++20中,当类型是可默认构造和可复制的时,你可以直接使用now-constexpr fill函数(live example)来为这个类型创建一个helper:

#include <array>
#include <concepts>
#include <cstddef>

template<std::size_t N, std::semiregular T>
constexpr auto array_repeat(const T& value) -> std::array<T, N> {
    std::array<T, N> ret;
    ret.fill(value);
    return ret;
}

int main() {
    constexpr auto a = array_repeat<3>(11);
    static_assert(a == std::array<int, 3>{11, 11, 11});
}

这可能会降低效率,但这是否是一个问题取决于您。

相关问题