std::array
可以用特定值构造(在较新的 C++ 版本的编译时),例如
std::array a{1, 4, 9};
但是 - 它没有构造函数,也没有标准库命名的构造函数习惯用法,采用单个值并复制它。即我们没有:
std::array<int, 3> a{11};
// a == std::array<int, 3>{11, 11, 11};
因此,我们如何构造一个只给出要重复的值的数组?
编辑:我正在寻找一种解决方案,即使对于不可默认构造的元素类型也适用;因此,通过默认构造数组然后填充它的解决方案不是我所追求的 - 尽管事实上这适用于
int
的情况(如示例中所示)。
我们可以编写一个适当的命名构造函数习惯用法来实现这一点。然后,您的示例定义将如下所示:
auto a = array_repeat<3>(11);
// a == std::array<int, 3>{11, 11, 11};
但是,实现有点笨拙,因为我们需要使用 “索引技巧”,这在 C++11 中需要大量样板,所以让我们假设 C++14:
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>());
}
备注:
tuple_repeat
,它是他的 C++11 元组实用程序的一部分。
array_repeat_impl
中的不当转发。
array_repeat()
函数可以获取右值引用并从中移动,因此可以在参数中创建临时值,即使它很昂贵。
fill
函数(现场示例)直接为此创建一个帮助器:
#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});
}
这可能会降低效率,但这是否是一个问题取决于您。