3 votes

Comment construire chacun des éléments d'un tableau membre avec l'argument du constructeur.

Duplicata possible :
Convertir std::tuple en std::array C++11

Supposons que vous ayez :

template<class T,int N>
struct A {
  A(const B& b): /* what comes here */ {}

  std::array<T,N> F;
};

J'ai besoin que chaque élément de F[] à construire avec l'argument du constructeur, dans le cas ci-dessus b . Ceci est délicat car l'argument peut ne pas être d'un type qui peut être une constante de temps de compilation, comme par exemple int etc.

C'est différent de Est-il possible de construire les éléments d'un tableau de membres en fonction d'un paramètre de modèle intégral ? puisqu'ici une structure définie par l'utilisateur est utilisée et que nous avons donc besoin de copies de celle-ci au moment de l'exécution.

8voto

Xeo Points 69818

L'astuce des indices peut être appliquée ici aussi, il suffit de la transformer un peu :

template <std::size_t... Is>
struct indices {};

template <std::size_t N, std::size_t... Is>
struct build_indices
  : build_indices<N-1, N-1, Is...> {};

template <std::size_t... Is>
struct build_indices<0, Is...> : indices<Is...> {};

template<class T,int N>
struct A {
  template<std::size_t... Is>
  A(const B& b, indices<Is...>) : F{{(void(Is),b)...}} {}
  A(const B& b) : A(b, build_indices<N>{}) {}

  std::array<T,N> F;
};

Exemple concret.

Nous ignorons fondamentalement les valeurs des indices et n'utilisons que le paquet lui-même pour effectuer l'expansion, c'est-à-dire que seule la taille du paquet nous intéresse. Réutiliser les indices pour cela peut sembler être un abus, puisque nous ne sommes pas intéressés par les valeurs réelles, mais je pense que réutiliser la machinerie ici est bien. Toute autre construction pour créer un N -Le paquet d'éléments aurait le même aspect, sauf que le paquet ne contiendrait probablement que des zéros.

0voto

bames53 Points 38303

L'astuce build_indicies montrée par Xeo est intelligente et probablement la meilleure option si votre compilateur la supporte.

Une autre option pourrait être de permettre aux éléments d'être construits par défaut, puis de les détruire et de les reconstruire avec placment new/uninitialized_fill :

template<class T,int N>
struct A {
  A(const B& b) {
      for (size_t i=0;i<N;++i) {
          F[i].~T();
          new (&F[i]) T(b);
      }
  }

  std::array<T,N> F;
};

Vous pourriez également utiliser un stockage qui ne serait pas initialisé normalement, pour éviter la construction par défaut :

template<class T,int N>
struct A {    
  typedef std::array<T,N> array_type;
  std::aligned_storage<sizeof(array_type),alignof(array_type)>::type storage;

  array_type &F() {
    return reinterpret_cast<array_type&>(storage);
  }

  A(const B& b) {
    // placement new/uninitialized_fill
  }
};

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