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

Langage C++ Discussion :

Problème de déduction de type template


Sujet :

Langage C++

  1. #1
    Membre émérite
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 764
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 764
    Points : 2 704
    Points
    2 704
    Par défaut Problème de déduction de type template
    Hello,

    J'ai un souci avec le code suivant, où le compilateur n'arrive pas à déduire le type T :

    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
    #include <iostream>
    #include <vector>
    #include <type_traits>
     
    namespace data
    {
    	struct Foo {};
     
    	template <typename T>
    	void func(const std::vector<typename std::enable_if<std::is_pod<T>::value, T>::type>& contents)
    	{
    		std::cout << "Blah" << std::endl;
    	}
    }
     
    int main()
    {
    	std::vector<data::Foo> vec;
    	func(vec);
    	return 0;
    }
    Vous pouvez le retrouver sur ideone.com.

    Merci pour votre aide, et pour la discussion probablement intéressante que nous allons initier.

  2. #2
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 189
    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 189
    Points : 17 141
    Points
    17 141
    Par défaut
    le compilateur ne peut déduire que les types "finaux".
    dans typename enable_if<Bidule, T>::type, le type final est ::type, qui n'est pas forcément T, il peut y avoir une spécialisation.

    A la louche, le compilateur ne peut pas déduire un type qui a besoin de typename.
    C'est d'ailleurs parce que le compilateur aura du mal à travailler avec cette chose qu'on doit lui préciser que c'est un type.

    Mais ton enable_if en type retour de la fonction, et ca ira mieux. (note, le ::type par défaut de enable_if est void, ca tombe bien)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    template <typename T>
    typename std::enable_if<std::is_pod<T>::value>::type
    func(const std::vector<T>& contents)
    Mes principes de bases du codeur qui veut pouvoir dormir:
    • Une variable de moins est une source d'erreur en moins.
    • Un pointeur de moins est une montagne d'erreurs en moins.
    • Un copier-coller, ça doit se justifier... Deux, c'est un de trop.
    • jamais signifie "sauf si j'ai passé trois jours à prouver que je peux".
    • La plus sotte des questions est celle qu'on ne pose pas.
    Pour faire des graphes, essayez yEd.
    le ter nel est le titre porté par un de mes personnages de jeu de rôle

  3. #3
    Membre émérite
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 764
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 764
    Points : 2 704
    Points
    2 704
    Par défaut
    Je ne peux pas.

    J'ai fait un exemple simplifié pour le forum, mais en fait, la fonction est l'opérateur de flux operator<< :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    template<typename T>
    inline std::ostream& operator<<(std::ostream& out, const std::vector<typename std::enable_if<!std::is_pod<T>::value, T>::type>& contents)
    {
    	out.put(sizeof(T));
    	size_t size = contents.size();
    	out.write(reinterpret_cast<const char*>(&size), sizeof(size_t));
     
    	for (const auto& spi : contents)
    	    out << spi;
     
    	return out;
    }
    Tu noteras que cette fonction doit être appelée quand le type n'est pas un POD (contrairement au premier exemple fourni).
    Quand j'ai un POD, je serialise ainsi :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    template<typename T>
    inline std::ostream& operator<<(std::ostream& out, const std::vector<T>& contents)
    {
        out.put(sizeof(T));
        size_t size = contents.size();
        out.write(reinterpret_cast<const char*>(&size), sizeof(size_t));
        out.write(reinterpret_cast<const char*>(contents.data()), contents.size()*sizeof(T));
        return out;
    }
    Dans le cas contraire, il faut être plus fin...

  4. #4
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 189
    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 189
    Points : 17 141
    Points
    17 141
    Par défaut
    Et ceci ne fonctionnerait pas?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    template<typename T>
    inline
    typename std::enable_if<!std::is_pod<T>::value, std::ostream&>::type
    operator<<(std::ostream& out, const std::vector<T>& contents) { //code si non pod }
     
    template<typename T>
    inline
    typename std::enable_if<std::is_pod<T>::value, std::ostream&>::type
    operator<<(std::ostream& out, const std::vector<T>& contents) { //code si pod }
    Mes principes de bases du codeur qui veut pouvoir dormir:
    • Une variable de moins est une source d'erreur en moins.
    • Un pointeur de moins est une montagne d'erreurs en moins.
    • Un copier-coller, ça doit se justifier... Deux, c'est un de trop.
    • jamais signifie "sauf si j'ai passé trois jours à prouver que je peux".
    • La plus sotte des questions est celle qu'on ne pose pas.
    Pour faire des graphes, essayez yEd.
    le ter nel est le titre porté par un de mes personnages de jeu de rôle

  5. #5
    Membre émérite
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 764
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 764
    Points : 2 704
    Points
    2 704
    Par défaut
    operator<< est supposé renvoyer std::ostream&, afin de pouvoir chaîner les appels.

  6. #6
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 189
    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 189
    Points : 17 141
    Points
    17 141
    Par défaut
    Oui, c'est le principe de même enable_if: bloquer les instanciations qui ne respècte pas une condition. Son usage est de remplacer un type dans la définition d'une fonction (ou d'une classe)

    enable_if<cond, T>::type est T si cond est vrai, non défini sinon.

    Donc typename enable_if< std::is_pod<T>::value, std::ostream&>::type est std::ostream& si T est is_pod, et ne compile pas sinon
    Grace à SFINAE, cette impossibilité de définir la template pour ce T précis n'est pas une erreur, si une autre template compile correctement.

    Les deux templates de fonctions de mon message précédents définissent deux templates de surcharges de <<. Elles retournent toutes deux des std::ostream& car c'est le type "résultat" du enable_if.


    enable_if se comporte comme suis:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    template<bool B, class T = void>
    struct enable_if {};
     
    template<class T>
    struct enable_if<true, T> { using type = T; };
    Mes principes de bases du codeur qui veut pouvoir dormir:
    • Une variable de moins est une source d'erreur en moins.
    • Un pointeur de moins est une montagne d'erreurs en moins.
    • Un copier-coller, ça doit se justifier... Deux, c'est un de trop.
    • jamais signifie "sauf si j'ai passé trois jours à prouver que je peux".
    • La plus sotte des questions est celle qu'on ne pose pas.
    Pour faire des graphes, essayez yEd.
    le ter nel est le titre porté par un de mes personnages de jeu de rôle

  7. #7
    Membre émérite
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 764
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 764
    Points : 2 704
    Points
    2 704
    Par défaut
    Ah oui, excuse-moi ! Je n'avais pas vu l'usage du second paramètre template de enable_if, que je ne connaissais pas.

    Je n'aurai pas le temps d'essayer ça aujourd'hui, mais je je vais essayer. Je te tiens au courant.

  8. #8
    Membre émérite
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 764
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 764
    Points : 2 704
    Points
    2 704
    Par défaut
    J'ai essayé ta solution, et j'ai le même souci... :-/

  9. #9
    Membre émérite
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 764
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 764
    Points : 2 704
    Points
    2 704
    Par défaut
    Voici la solution :

    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
    #include <iostream>
    #include <vector>
    #include <type_traits>
     
    namespace data
    {
    	struct Foo {};
     
    	template <typename T, typename U = typename std::enable_if<std::is_pod<T>::value>::type>
    	void func(const std::vector<T>& contents)
    	{
    		std::cout << "Blah" << std::endl;
    	}
    }
     
    int main()
    {
    	std::vector<data::Foo> vec;
    	func(vec);
    	return 0;
    }
    Selon si on met ou non un ! avant std::is_pod, cela compile ou pas.

    Cela dit, je pense que ta solution est tout de même supposée fonctionner.
    Je vais fouiller un peu plus...

  10. #10
    Invité
    Invité(e)
    Par défaut
    Bonsoir,

    Hormis dans certains cas, il y a trois solutions. Cf. Est-il possible de faire une spécialisation partielle d'une fonction ?
    Dernière modification par Invité ; 21/01/2017 à 01h01.

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

Discussions similaires

  1. Réponses: 12
    Dernier message: 02/12/2010, 11h36
  2. Réponses: 2
    Dernier message: 17/10/2010, 15h11
  3. [phpBB] Function avec le Template phpBB
    Par mangafan dans le forum EDI, CMS, Outils, Scripts et API
    Réponses: 5
    Dernier message: 27/09/2005, 16h32
  4. Problème de requete avec type monétaire
    Par Pymm dans le forum ASP
    Réponses: 11
    Dernier message: 09/09/2005, 16h57
  5. Problème de champs Paradox type : mémo formaté
    Par mjp dans le forum Bases de données
    Réponses: 6
    Dernier message: 05/04/2005, 21h13

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