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

Boost C++ Discussion :

concept_check et SFINAE


Sujet :

Boost C++

  1. #1
    Membre éclairé
    Avatar de Florian Goo
    Profil pro
    Inscrit en
    Septembre 2008
    Messages
    680
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Septembre 2008
    Messages : 680
    Points : 858
    Points
    858
    Par défaut concept_check et SFINAE (edit : et C++0x aussi)
    Salut à tous,

    Je fais peu à peu mon deuil de la non inclusion des concepts dans C++0x en me penchant sur boost::concept_check, qui a finalement l'air intéressant.

    Peut-on surcharger une fonction en utilisant concept_check et le mécanisme SFINAE ?
    J'ai pensé que la simple utilisation de concept_check permettait ça (car tout est inclus dans la signature de la fonction), mais il semblerait que non :
    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
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
     
    #include <iostream>
    #include <boost/concept_check.hpp>
    #include <boost/concept/requires.hpp>
     
    class integer
    {
    	public:
    		integer(int value):
    			value_(value)
    		{
    		}
     
    		int
    		value() const
    		{
    			return value_;
    		}
     
    	private:
    		int value_;
    };
     
    bool
    operator==(const integer& i, const integer& j)
    {
    	return i.value() == j.value();
    }
     
    template<typename T>
    class Comparable
    {
    	public:
    		BOOST_CONCEPT_USAGE(Comparable)
    		{
    			t1 == t2;
    		}
     
    	private:
    		T t1;
    		T t2;
    };
     
    template<typename T>
    class JavaStyleComparable
    {
    	public:
    		BOOST_CONCEPT_USAGE(JavaStyleComparable)
    		{
    			t1.equals(t2);
    		}
     
    	private:
    		T t1;
    		T t2;
    };
     
    template<typename T>
    BOOST_CONCEPT_REQUIRES
    (
    	((Comparable<T>)),
    	(bool)
    )
    same_value(const T& t1, const T& t2)
    {
    	return t1 == t2;
    }
     
    template<typename T>
    BOOST_CONCEPT_REQUIRES
    (
    	((JavaStyleComparable<T>)),
    	(bool)
    )
    same_value(const T& t1, const T& t2)
    {
    	return t1.equals(t2);
    }
     
    int
    main()
    {
    	integer i(0);
    	integer j(0);
     
    	if(same_value(i, j))
    	{
    		std::cout << "woohoo!\n";
    	}
    	else
    	{
    		std::cout << "d'oh!\n";
    	}
     
    	return 0;
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    main.cpp|85| error: call of overloaded ‘same_value(integer&, integer&)’ is ambiguous
    main.cpp|63| note: candidates are: typename boost::Requires_<(0 + boost::_requires_::value), void (*)(bool)>::type same_value(const T&, const T&) [with T = integer]
    main.cpp|74| note:                 typename boost::Requires_<(0 + boost::_requires_::value), void (*)(bool)>::type same_value(const T&, const T&) [with T = integer]
    || main.cpp: In destructor ‘JavaStyleComparable<T>::~JavaStyleComparable() [with T = integer]’:
    /usr/include/boost/concept/detail/general.hpp|29| instantiated from ‘static void boost::concept::requirement<Model>::failed() [with Model = JavaStyleComparable<integer>]’
    /usr/include/boost/concept/requires.hpp|31| instantiated from ‘boost::_requires_<void (*)(JavaStyleComparable<integer>)>’
    main.cpp|85| instantiated from here
    main.cpp|49| error: ‘class integer’ has no member named ‘equals’
    J'ai parcouru la doc et je n'ai pas vu un tel cas d'utilisation. On peut faire quelque chose en ajoutant du enable_if ? Si oui comment ?
    Cours : Initiation à CMake
    Projet : Scalpel, bibliothèque d'analyse de code source C++ (développement en cours)
    Ce message a été tapé avec un clavier en disposition bépo.

  2. #2
    Membre éclairé
    Avatar de Florian Goo
    Profil pro
    Inscrit en
    Septembre 2008
    Messages
    680
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Septembre 2008
    Messages : 680
    Points : 858
    Points
    858
    Par défaut
    Bon. Déjà le couple concept_check/enable_if, c'est mouru :
    Citation Envoyé par Dave Abrahams
    on Wed Jan 30 2008, Johan Torp <johan.torp-AT-gmail.com> wrote:

    > Is there any way to combine boost::enable_if and the concept check library?
    > For instance to disable a function overload for template parameters which
    > doesn't model some STL concept.

    Nope. Those concepts perform checks that cause hard compile-time
    errors. Once they've failed, it's too late to recover... and not all
    concept check failures can be converted to non-error true/false results
    in C++03.
    http://lists.boost.org/Archives/boos.../01/132842.php


    Et pour SFINAE tout court, j'en ai aussi bien l'impression.
    Cours : Initiation à CMake
    Projet : Scalpel, bibliothèque d'analyse de code source C++ (développement en cours)
    Ce message a été tapé avec un clavier en disposition bépo.

  3. #3
    Membre averti
    Profil pro
    professeur des universités à la retraite
    Inscrit en
    Août 2008
    Messages
    364
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : professeur des universités à la retraite

    Informations forums :
    Inscription : Août 2008
    Messages : 364
    Points : 439
    Points
    439
    Par défaut
    Que veux-tu dire en ce qui concerne SFINAE ? C'est une technique de programmation comment ça pourrait "mouruir" ?

  4. #4
    Membre éclairé
    Avatar de Florian Goo
    Profil pro
    Inscrit en
    Septembre 2008
    Messages
    680
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Septembre 2008
    Messages : 680
    Points : 858
    Points
    858
    Par défaut
    Pardonne-moi mais je n'ai pas compris ta question ?
    Cours : Initiation à CMake
    Projet : Scalpel, bibliothèque d'analyse de code source C++ (développement en cours)
    Ce message a été tapé avec un clavier en disposition bépo.

  5. #5
    Membre chevronné
    Avatar de Goten
    Profil pro
    Inscrit en
    Juillet 2008
    Messages
    1 580
    Détails du profil
    Informations personnelles :
    Âge : 33
    Localisation : France

    Informations forums :
    Inscription : Juillet 2008
    Messages : 1 580
    Points : 2 205
    Points
    2 205
    Par défaut
    Citation Envoyé par ptyxs Voir le message
    Que veux-tu dire en ce qui concerne SFINAE ? C'est une technique de programmation comment ça pourrait "mouruir" ?

    Il parlait de l'utilisation conjointe de boost::enable_if et concept_check. C'est "mourru" dans le sens c'est pas possible .

    Quand a flo : euh non là sur le coup jvois pas :s.
    "Hardcoded types are to generic code what magic constants are to regular code." --A. Alexandrescu

  6. #6
    Membre éclairé
    Avatar de Florian Goo
    Profil pro
    Inscrit en
    Septembre 2008
    Messages
    680
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Septembre 2008
    Messages : 680
    Points : 858
    Points
    858
    Par défaut
    J'ai causé un peu avec Alp et il m'a parlé de ça :
    http://www.open-std.org/jtc1/sc22/wg...008/n2634.html
    Du SFINAE pour les expressions.

    Vu que le principe de concept_check (et en particulier de BOOST_CONCEPT_REQUIRES) est d'imposer une série d'instruction dans la signature de la fonction, ça m'a l'air d'être la bonne feature pour permettre une surcharge de fonctions comme je le souhaite et comme les concepts de C++0x le promettaient.
    D'ailleurs loufoque en causait furtivement ici, mais ça m'est passé sous le nez : http://www.developpez.net/forums/d77...s/#post4520427

    Y'a bon.
    Cours : Initiation à CMake
    Projet : Scalpel, bibliothèque d'analyse de code source C++ (développement en cours)
    Ce message a été tapé avec un clavier en disposition bépo.

  7. #7
    Membre éclairé
    Avatar de Florian Goo
    Profil pro
    Inscrit en
    Septembre 2008
    Messages
    680
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Septembre 2008
    Messages : 680
    Points : 858
    Points
    858
    Par défaut
    Euh non attendez, pas du tout…
    http://gcc.gnu.org/projects/cxx0x.html
    GCC 4.4, qui est le compilo que j'utilise, implémente déjà la fonctionnalité « Solving the SFINAE problem for expressions ».

    J'ai activé C++0x et l'erreur est toujours présente.


    En me basant sur l'exemple donné dans le proposal, j'écris un code complet pour tester :
    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
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    #include <iostream>
     
    struct X
    {
    	X(int value):
    		value_(value)
    	{
    	}
     
    	int value_;
    };
     
    X
    operator*(X x1, X x2)
    {
    	return X(x1.value_ * x2.value_);
    }
     
     
     
    struct Y
    {
    	Y(int value):
    		value_(value)
    	{
    	}
     
    	int value_;
    };
     
    Y
    operator+(Y y1, Y y2)
    {
    	return Y(y1.value_ + y2.value_);
    }
     
     
     
    template<class T>
    auto
    f(T t1, T t2) -> decltype(t1 + t2) // #1
    {
    	std::cout << "#1\n";
    	return t1 + t2;
    }
     
    template<class T>
    auto
    f(T t1, T t2) -> decltype(t1 * t2) // #2
    {
    	std::cout << "#2\n";
    	return t1 * t2;
    }
     
    int main()
    {
    	X x1(0), x2(0);
    	X x3 = f(x1, x2); // deduction fails on #1 (cannot add X+X), calls #2
     
    	Y y1(0), y2(0);
    	Y y3 = f(y1, y2); // calls #1
    }
    Non seulement ça compile, mais en plus j'ai bien la sortie attendue :
    Donc ça fonctionne bien.

    On est obligé d'utiliser decltype, donc ?
    Et si on veut surcharger une fonction qui renvoie void, on fait comment ?
    Cours : Initiation à CMake
    Projet : Scalpel, bibliothèque d'analyse de code source C++ (développement en cours)
    Ce message a été tapé avec un clavier en disposition bépo.

  8. #8
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut
    Citation Envoyé par Florian Goo Voir le message
    Et si on veut surcharger une fonction qui renvoie void, on fait comment ?
    Comme ça ?
    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
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    #include <iostream>
     
    struct X
    {
    	X(int value):
    		value_(value)
    	{
    	}
     
    	int value_;
    };
     
    void
    operator*(X x1, X x2)
    {
    	X(x1.value_ * x2.value_);
    }
     
     
     
    struct Y
    {
    	Y(int value):
    		value_(value)
    	{
    	}
     
    	int value_;
    };
     
    void
    operator+(Y y1, Y y2)
    {
    	Y(y1.value_ + y2.value_);
    }
     
     
     
    template<class T>
    auto
    f(T t1, T t2) -> decltype(t1 + t2) // #1
    {
    	std::cout << "#1\n";
    	return t1 + t2;
    }
     
    template<class T>
    auto
    f(T t1, T t2) -> decltype(t1 * t2) // #2
    {
    	std::cout << "#2\n";
    	return t1 * t2;
    }
     
    int main()
    {
    	X x1(0), x2(0);
    	f(x1, x2); // deduction fails on #1 (cannot add X+X), calls #2
     
    	Y y1(0), y2(0);
    	f(y1, y2); // calls #1
    }

  9. #9
    Alp
    Alp est déconnecté
    Expert éminent sénior

    Avatar de Alp
    Homme Profil pro
    Inscrit en
    Juin 2005
    Messages
    8 575
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Juin 2005
    Messages : 8 575
    Points : 11 860
    Points
    11 860
    Par défaut
    Tu t'en fous que ce soit void ou autre chose. void n'est qu'un type au milieu de tant d'autres.

    Donc SFINAE pour les expressions bien qu'un poil différent des concepts va pas mal aider. Je ne savais pas que g++4.4 l'implémentait par contre, merci du tuyau ! Je vais voir pour rédiger un petit truc là-dessus

  10. #10
    Membre éclairé
    Avatar de Florian Goo
    Profil pro
    Inscrit en
    Septembre 2008
    Messages
    680
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Septembre 2008
    Messages : 680
    Points : 858
    Points
    858
    Par défaut
    Certes, mais si on est obligé de passer par auto/decltype, ça sera une bidouille bien cradingue…
    Cours : Initiation à CMake
    Projet : Scalpel, bibliothèque d'analyse de code source C++ (développement en cours)
    Ce message a été tapé avec un clavier en disposition bépo.

  11. #11
    Membre éclairé
    Avatar de Florian Goo
    Profil pro
    Inscrit en
    Septembre 2008
    Messages
    680
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Septembre 2008
    Messages : 680
    Points : 858
    Points
    858
    Par défaut
    Je bidouille un peu, apparemment une signature type « auto/decltype » n'est pas requise :
    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
    31
    32
    33
    template<typename>
    class require
    {
    	public:
    		typedef void* type;
    };
     
    //#1
    template<class T>
    T
    f(T t1, T t2, typename require<decltype(t1 * t2)>::type = 0)
    {
    	std::cout << "#1\n";
    	return t1 * t2;
    }
     
    //#2
    template<class T>
    T
    f(T t1, T t2, typename require<decltype(t1 + t2)>::type = 0)
    {
    	std::cout << "#2\n";
    	return t1 + t2;
    }
     
    int main()
    {
    	X x1(0), x2(0);
    	Y y1(0), y2(0);
     
    	X x3 = f(x1, x2); //calls #1
    	Y y3 = f(y1, y2); //calls #2
    }
    C'est mieux .
    Cours : Initiation à CMake
    Projet : Scalpel, bibliothèque d'analyse de code source C++ (développement en cours)
    Ce message a été tapé avec un clavier en disposition bépo.

  12. #12
    Membre éclairé
    Avatar de Florian Goo
    Profil pro
    Inscrit en
    Septembre 2008
    Messages
    680
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Septembre 2008
    Messages : 680
    Points : 858
    Points
    858
    Par défaut
    Puisque la question initiale a eu sa réponse et puisqu'il ne s'agit plus de Boost, je vous invite à continuer la discussion ici : http://www.developpez.net/forums/d84...r-expressions/
    De plus, la visibilité du sujet n'en sera que meilleure !
    Cours : Initiation à CMake
    Projet : Scalpel, bibliothèque d'analyse de code source C++ (développement en cours)
    Ce message a été tapé avec un clavier en disposition bépo.

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

Discussions similaires

  1. SFINAE. (je ne comprend pas)
    Par Invité dans le forum Langage
    Réponses: 8
    Dernier message: 19/08/2014, 11h04
  2. Visibilité de template et SFINAE
    Par vikki dans le forum Langage
    Réponses: 8
    Dernier message: 06/07/2011, 13h54
  3. Réponses: 6
    Dernier message: 04/01/2010, 02h35

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