Como posso construir um std :: array preenchido com algum valor uniforme?
std::array pode ser construído (em tempo de compilação com versões mais recentes de C ++) com valores específicos, por exemplo
std::array a{1, 4, 9};
no entanto - ele não tem um construtor ou uma biblioteca padrão chamada constructor idiom, pegando um único valor e replicando-o. ou seja, não temos:
std::array<int, 3> a{11};
// a == std::array<int, 3>{11, 11, 11};
Como podemos, portanto, construir um array dado apenas o valor a ser repetido?
Edit: Estou procurando uma solução que funcione mesmo para tipos de elemento que não são construtíveis padrão; então, uma solução construindo o array padrão e, em seguida, preenchendo-o, não é o que eu procuro - apesar do fato de que funcionará no caso de int(como no exemplo).
Respostas
Podemos escrever um idioma de construtor nomeado apropriado para conseguir
A implementação é um pouco desajeitada, no entanto, já que precisamos usar o "truque dos índices" que exige muitos clichês em C ++ 11, então vamos supor que 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>());
}
Veja isso funcionando GodBolt.
Se você pode compilar seu código C ++ 20, pode abandonar a dependência make_arraye escrever:
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
Notas:
- Esta solução é um pouco semelhante à de Jared Hoberock
tuple_repeat, parte de seus utilitários de tupla para C ++ 11 . - Os agradecimentos vão para @Caleth e @LF por apontar um encaminhamento inadequado no
array_repeat_impl.
Com C ++ 20, você pode fazer um auxiliar para isso diretamente quando o tipo for construtível por padrão e copiável usando a fillfunção now-constexpr ( exemplo ao vivo ):
#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});
}
Isso poderia ser menos eficiente, mas você decide se isso é um problema.