IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C++ Discussion :

constructeur à N arguments, N étant un paramêtre template


Sujet :

C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Expert éminent

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 202
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 202
    Par défaut constructeur à N arguments, N étant un paramêtre template
    Je développe actuellement une bibliothèque de géométrie ND (2D, 3D et 4D, principalement), dont voici un extrait.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    using dimension_type = std::size_t;
     
    // constexpr compatible mathematical N-dimensional vector
    template <typename Value, dimension_type Dimensions>
    class vector {
      static_assert(Dimensions > 0, "No support for 0D (or less) vectors");
    public:
      using value_type = Value;
     
      value_type values[Dimensions];
      //agregate initialization
     
      constexpr value_type const& operator[](dimension_type i) const { return values[i]; }
      value_type& operator[](dimension_type i) { return values[i]; }
     
      vector& operator += (vector const& other) { for (dimension_type i = 0; i < Dimensions; ++i) (*this)[i] += other[i]; return *this; }
     
      constexpr vector add(vector const& other) const { return add(other, make_index_sequence()); }
     
    private:
      using make_index_sequence = std::make_integer_sequence<dimension_type, Dimensions>;
      template<dimension_type... i>
      using index_sequence = std::integer_sequence<dimension_type, i...>;
     
      template<dimension_type... i>
      constexpr vector add(vector const& other, index_sequence<i...>) const { return vector{ ((*this)[i] + other[i])... }; }
    };
     
    template <typename Value, dimension_type dimensions>
    constexpr inline vector<Value, dimensions> operator + (vector<Value, dimensions> const& a, vector<Value, dimensions> const& b) { return a.add(b); }
    J'ai beau chercher, je ne vois pas comment écrire mes constructeurs, avec les contraintes suivantes:
    1. Ils doivent être constexpr c'est "vital"
    2. vector<double, 2> v; doit compiler et être {0, 0} (pas comme std::array)
    3. vector<double, 3> k{0,0,1}; doit être possible
    4. vector<double, 3> v{0, 1}; ne doit pas compiler, car il manque une composante. (pas comme std::array)
    5. f(vector<double, 3>); f({0, 1, 2}); doit compiler, sans avoir à préciser le type (f(vector<double, 3>{0,1,2})


    Précisément, je ne sais pas comment écrire mon constructeur à N paramètres.
    J'ai essayé avec l'"aggregate initialization", mais je n'ai pas le point 4
    J'ai essayé avec un constructeur template variadique, mais le point 5 saute.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    template <typename T...>
    constexpr vector(T... args): values{args...} {
      static_assert(plein de choses);
    }
    J'essaye avec std::initializer_list, mais le point 4 compile (j'ai seulement une exception).

    Avez-vous une idée?

  2. #2
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Salut,

    (petite correction "purement sémantique" : envisage peut être de nommer ton deuxième paramètre template "count" au lieu de dimensions, cela évitera la confusion nombre d'élément Vs tableau multi dimentionnel)

    Sinon, je me demande (il faudra tester) si un code proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
     
    template <typename Needed, typename T, typename ... Others>
    struct TypeChecker{
         template <
         static constexpr void check(){
             TypeChecker<Needed, T>::check();
             TypeChecker<Needed, Other ...>::check();
         }
    };
    template <typename Needed, typename T>
    struct TypeChecker<Needed, T>{
        static constexpr void check(){
            static_assert(std::is_same_v(Needed, T);
        }
    }
     
    template <typename T, dimension_type Count>
    class vector{
        static_assert(Dimensions > 0, "No support for 0D (or less) vectors");
    public: 
        vector(T all=T{}); // constructeur par défaut + constructeur permettant de définir une valeur unique pour tous les éléments
        template <typename ... Args>
        vector(Args ... args){
            static_assert(sizeof...(Args) == Count,
                               "bad parameter count");
            TypeChecker<T, Args ...>::check();
        }
        /* ... */
    };
    ne pourrait pas faire l'affaire

    Au passage, pourquoi n'utiliserais tu pas std::array pour représenter tes données, car, lui, il implémente déjà l'agregate initialization, et cela te faciliterait surement la vie

    Ton code pourrait alors prendre une forme proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    template <typename T, dimension_type Count>
    class vector{
    public:
        vector():datas_{}{}
        template <typename ... Args>
        vector(Args ... args):datas_{args ...}{
        }
    private:
        std::array<T, Count> datas_;
    };
    Et le tour serait joué
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  3. #3
    Expert éminent

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 202
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 202
    Par défaut
    A priori, parce qu'il y a un gros soucis avec std::array: l'aggregate initialization accepte un nombre trop bas d'arguments.
    Cela dit, vu la forme que ca prend, c'est envisageable, maintenant.

    Je vais étudier ta proposition.
    Peut-être aussi ajouter un enable_if, pour que le check soit fait avant l'exécution de l'initialization.

  4. #4
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Je tiens quand même à être clair: j'ai écrit ce code à la volée, et je ne l'ai absolument pas testé. quelques adaptations sont peut-être nécessaires

    quant à enable_if, je t'avouerai que j'ai un peu de mal à voir comment tu t'y prendrais

    Par contre, ce que tu pourrais envisager de faire, ce serait d'avoir un code proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    template < dimension_type Count>
    struct CountChecker{
        CountChecker(){}
        template <typename ... Args>
        CountChecker(Args ...){
            static_assert(sizeof...(Args)==count);
        }
    };
    template <typename T, dimension_type Count>
    class vector : private CountChecker<Count>{
    public:
        vector():CountChecker<Count>(){}
        template <typename ... Args>
        vector(Args ... args):CountChecker<Count>(arg),/* ... */{
        }
    };
    Encore une fois, le code n'a pas été testé, et il a été écrit "à la volée", avec tout ce que cela peut impliquer
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  5. #5
    Membre Expert
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2011
    Messages
    760
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2011
    Messages : 760
    Par défaut
    Une solution avec static_assert va poser quelques soucis avec la surcharge. Par exemple f(vector<double, 3>); et f(vector<double, 2>); vont correspondre toutes les 2 et il y aura une erreur de compilation contrairement à enable_if qui va filtrer les prototypes.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    template<class T, size_t Dim>
    struct vector
    {
        vector() = default;
     
        template<class... U, class = std::enable_if_t<sizeof...(U) == Dim>>
        constexpr vector(U...)
        {}
     
        std::array<T, Dim> values {};
    };

  6. #6
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Oh, si un code proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    template<class... U, class = std::enable_if_t<sizeof...(U) == Dim>>
    fonctionne, alors allons y gaiement

    Mais (je peux me tromper, bien sur ) il me semblait avoir expériementé quelque problèmes en essayant de rajouter un paramètre template (fut-il défini par défaut) après un parameter pack
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 3
    Dernier message: 16/01/2018, 16h58
  2. Template C++ constructeur avec arguments
    Par oc_alex86 dans le forum Débuter
    Réponses: 6
    Dernier message: 06/11/2010, 14h45
  3. Passage d'une fonction en tant que paramètre
    Par bagnolm dans le forum Langage
    Réponses: 3
    Dernier message: 28/11/2006, 15h58
  4. Déclarer un paramètre template comme friend
    Par YéTeeh dans le forum Langage
    Réponses: 4
    Dernier message: 11/04/2006, 14h00
  5. X paramètres templates
    Par Alp dans le forum C++
    Réponses: 8
    Dernier message: 04/04/2006, 22h10

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo