7 votes

Comment puis-je construire un std::array rempli d'une valeur uniforme ?

std::array peuvent être construits (au moment de la compilation avec les nouvelles versions de C++) avec des valeurs spécifiques, par ex.

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

Cependant, il ne dispose pas d'un constructeur, ou d'un idiome de constructeur nommé standard, prenant une valeur unique et la répliquant, c'est-à-dire que nous n'avons pas.. :

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

Comment pouvons-nous, dès lors, construire un tableau en ne donnant que la valeur à répéter ?

Editar: Je cherche une solution qui fonctionnerait même pour les types d'éléments qui ne sont pas constructibles par défaut ; ainsi, une solution consistant à construire par défaut le tableau, puis à le remplir, n'est pas ce que je recherche - malgré le fait que cela fonctionnera dans le cas de int (comme dans l'exemple).

9voto

einpoklum Points 2893

Nous pouvons écrire un idiome du constructeur nommé pour y parvenir

L'implémentation est cependant un peu compliquée, car nous devons utiliser la fonction "truc d'indices" qui prend beaucoup de place dans C++11, alors supposons 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>());
}

Voir ce travail sur GodBolt .

Si vous pouvez compiler votre code en C++20, vous pouvez supprimer la dépendance à l'égard de make_array et écrire :

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

Notes :

  • Cette solution est quelque peu similaire à celle de Jared Hoberock tuple_repeat qui fait partie de son Utilitaires de tuple pour C++11 .
  • Merci à @Caleth et @L.F. pour avoir signalé une redirection inappropriée dans array_repeat_impl .

2voto

chris Points 28950

Avec C++20, vous pouvez créer une aide pour cela de manière directe lorsque le type est constructible par défaut et copiable en utilisant le désormais-constexpr fill fonction ( exemple concret ) :

#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});
}

Cela pourrait être moins efficace, mais c'est à vous de voir si c'est un problème.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X