2015-12-01 2 views
10

Je voudrais convertir un std::array en un autre std::array, en multipliant chacun de ses éléments par un nombre spécifique.Multiplier chaque élément d'un tableau std :: au moment de la compilation

Ce que j'ai maintenant droit ne fonctionne évidemment pas:

#include <array> 
#include <iostream> 
#include <utility> 

template <class T, size_t... Is, size_t N> 
constexpr std::array<T, N> multiply(std::array<T, N> const &src, 
            std::index_sequence<Is...>) { 
    return std::array<T, N>{{src[Is]...}}; // How can I multiply each of src's elements? 
} 

int main(int argc, char *argv[]) { 
    constexpr std::array<int, 3> arr = {1, 2, 3}; 
    constexpr auto t = multiply(arr, std::make_index_sequence<3>{}); 
    for (auto &el : t) std::cout << el << std::endl; 
    return 0; 
} 

Ma question est: comment puis-je itérer sur chaque élément au moment de la compilation ou comment puis-je appliquer la même fonction (dans mon cas: multiplier par 2) au moment de la compilation?

Répondre

14

Vous pouvez le faire de la façon suivante:

template<typename T> 
constexpr T mult(T const &a, T const &b) { return a * b; } 

template <class T, size_t... Is, size_t N> 
constexpr std::array<T, N> multiply(std::array<T, N> const &src, 
            std::index_sequence<Is...>) { 
    return std::array<T, N>{{mult(src[Is], src[Is])...}}; 
} 

Live Demo

Ou si vous voulez multiplier par un numéro que vous pouvez changer:

template<typename T> 
constexpr T mult(T const &a, T const &b) { return a * b; } 

template <class T, size_t... Is, size_t N> 
constexpr std::array<T, N> multiply(std::array<T, N> const &src, 
            std::index_sequence<Is...>, T const &mul) { 
    return std::array<T, N>{{mult(src[Is], mul)...}}; 
} 

Live Demo

Comme expliqué dans cppreference:Un motif suivi d'une ellipse, dans lequel le nom d'au moins un jeu de paramètres apparaît au moins une fois, est développé en zéro ou plusieurs instanciations séparées par des virgules du modèle, où le nom du jeu de paramètres est remplacé par chacun des types de la meute, dans l'ordre. Les extensions de pack ne peuvent avoir lieu que dans des contextes d'extension de pack. Ce sont essentiellement:

  • entretoisés initialisation
  • listes de initialiseur
  • des initialisations globales
  • fonction appelle
  • initialisations de réseau

Edit:

As T.C. a souligné dans les commentaires que vous pouvez aussi le faire aussi simple que:

template <class T, size_t... Is, size_t N> 
constexpr std::array<T, N> multiply(std::array<T, N> const &src, std::index_sequence<Is...>, T const &mul) { 
    return std::array<T, N>{{(src[Is] * mul)...}}; 
} 

Live Demo

+0

Comment la '{{mult (src [est], src [est]) ...}' travail partiel exactement ? Le '...' est un peu déroutant dans ce cas. – syntagma

+0

@REACHUS C'est l'une des façons d'étendre les packs. Attends, je vais essayer d'expliquer. – 101010

+0

Merci, encore une question: y aurait-il un moyen de remplacer 'mult' avec un lambda? Je l'ai essayé mais il semble que ce ne sera pas possible, puisque les lambdas ne peuvent pas être "constexpr's. – syntagma