guillaumebelz.github.io

Le code proposé par SirSamuHell

#include <iostream>
#include <array>
#include <vector>
#include <algorithm>
#include <numeric>
 
namespace utils 
{
    constexpr int TAILLE = 6;
    
    constexpr int sum(const std::array<int, TAILLE> t)
    {
        return std::accumulate(t.begin(), t.end(), 0);
    }
    
    constexpr int max (std::array<int, TAILLE> t)
    {
        return *std::max_element(t.begin(), t.end());
    }
    
    constexpr std::array<int, TAILLE> inverse(std::array<int, TAILLE> t)
    {
        std::reverse(t.begin(), t.end());
        return t;
    }
    
    constexpr std::array<int, TAILLE> multiply(std::array<int, TAILLE> t, const int k)
    {
        for(auto& e : t)
            e *= k; // pas trouver de fonction dans la STL...
            
        std::array<int, TAILLE> cpy;
        
        std::copy(t.begin(), t.end(), cpy.begin());
        return cpy;
    }
 
    constexpr std::array<int, TAILLE> unique(std::array<int, TAILLE> t)
    {
        (void)t;
        
        for(auto i = 0; i < TAILLE; i++)
        {
            for(auto j = 0; j < TAILLE; j++)
            {
                if(t[i] == t[j] && j != i)
                {
                    t[j] = -1;
                }
            }
        }
        
        return t;
    } 
}

using namespace utils; // Pour la fonction inverse qui est écrit sans utils

int main() {
    // Initialization et création du tableau d'entier 
    constexpr std::array<int, utils::TAILLE> t {1, 3, 2, 5, 3, 2};
  
    // calcule la somme des éléments
    constexpr auto s { utils::sum(t) };
    (void)s;    
 
    // recherche la valeur maximale
    constexpr auto m { utils::max(t) };
    (void)m;
 
    // inverse l'ordre des éléments du tableau (le premier devient le dernier, etc)
    constexpr auto t2 { inverse(t) };
    (void)t2;
    // multiplie chaque élément par une valeur constante
    utils::multiply(t, 2);
 
    // supprime les doublons
   
    constexpr auto  t3 { utils::unique(t) };
    (void)t3;
}

Mes commentaires

constexpr int sum(const std::array<int, TAILLE> t)
...
constexpr int max (std::array<int, TAILLE> t)
std::accumulate(t.begin(), t.end(), 0);
// préférer :
std::accumulate(std::begin(t), std::end(t), 0);
Template<typename ARRAY_TYPE>
constexpr int sum(const ARRAY_TYPE& t)
return *std::max_element(t.begin(), t.end());

Par contre, ton code sera moins resistant aux évolutions. Imagine par exemple que TAILLE devienne un paramètre template ou que std::array soit remplacé par std::vector. (Imagine en particulier si tu fais un rechercher-remplacer global dans un projet). Dans ce cas, ton code devient invalide. Est-ce un problème ? Ca depend :)

Quand on fait évoluer un code, il peut se passer : le code accepte sans problème le changement, ou le code signale qu’il y a un problème, ou le code ne signale pas qu’il y a problème (ie tu passes du temps a debugger, parfois des heures ou des jours sur un vrai projet, pour trouver l’erreur). Faire un code qui accepte les changements est parfois plus complexe a écrire (par exemple en transformant la fonction en template) mais c’est le mieux. Le pire, c’est un code qui ne signale pas du tout les problèmes.

Idem pour les types de retour. Si tu changes ton array<int, N> par array<float, N>, le type de retour n’est plus valide. Si tu utilises auto, le type sera automatique.

Ici, par exemple, le minimum, c’est au moins de vérifier les préconditions de ta fonction. Par exemple :

constexpr auto max (std::array<int, TAILLE> t)
{
    assert(!std::empty(t)); // verification que la taille n'est pas nulle
    return *std::max_element(std::begin(t), std::end(t));
}

Ou

constexpr auto max (std::array<int, TAILLE> t)
{
    constexpr auto it = std::max_element(std::begin(t), std::end(t);
    assert(it != std::end(t)); // verification que l'itérateur est valide avant de le déréférencer
    return *it;
}
constexpr auto inverse(std::array<int, TAILLE> t)
{
    return std::ranges::reverse_view{t};
}
// pas trouver de fonction dans la STL...
 constexpr std::array<int, TAILLE> multiply(std::array<int, TAILLE> t, const int k)
...
    std::array<int, TAILLE> cpy;
 constexpr auto multiply(std::array<int, TAILLE> t, const int k)
...
    decltype(t) cpy;

Si tu veux rendre ta fonction template, il faudra utiliser un template template ou value_type :

Template<template<typename T> class array_type>
constexpr auto multiply(const array_type<T>& t, const T& k)
...
    array_type<T> cpy;

Ou

Template<template array_type>
constexpr auto multiply(const array_type& t, const typename array_type::value_type& k)
...
    array_type cpy;
(void)t;
for(auto i = 0; i < TAILLE; i++)
t[j] = -1;
constexpr std::vector<int> unique(std::array<int, TAILLE> t)
for(auto i = 0; i < TAILLE; i++)
{
    for(auto j = i+1; j < TAILLE; j++)
    {
        if(t[i] == t[j])
using namespace utils; // Pour la fonction inverse qui est écrit sans utils

En tout cas, tu as les bases pour cet exo. La suite pour progresser, c’est la généricité, mais c’est le sujet de l’exo 3. Bon boulot !