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 :

Erreur interne au compilateur


Sujet :

C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé
    Profil pro
    Inscrit en
    Mai 2007
    Messages
    159
    Détails du profil
    Informations personnelles :
    Localisation : France, Moselle (Lorraine)

    Informations forums :
    Inscription : Mai 2007
    Messages : 159
    Par défaut Erreur interne au compilateur
    Bonjour,

    Voici le code que je compile. Il s'agît d'une simplification d'un truc plus gros :
    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 <class T>
    struct Test {
        template <unsigned _Vb, typename d=void>
        static constexpr unsigned U=
                /*Test<T>::*/U<_Vb-1,d>+2;
    };
     
    //template< class T>
    template <typename p>
    constexpr unsigned Test/*<T>*/::U<0,p> = 5;
     
    int main ()
    {
        enum class test { Debut,A=Debut,B,Fin };
        Test/*<test>*/ testDef;
    }
    Première question : Si je retire tous les commentaires j'obtiens une erreur interne du compilateur ci-après citée (j'utilise QTCreator 4.10/QT5.13.1/MinGW 7.3.0 64b). Ca me l'a également fait en 32b. Quelqu'un pourrait-il me dire si cette erreur se reproduit également gcc gcc/linux?
    07:44:13: Exécution des étapes pour le projet Orientation...
    07:44:13: Configuration inchangée, étape qmake sautée.
    07:44:13: Débute : "D:\Qt\App\Tools\mingw730_64\bin\mingw32-make.exe" -f Makefile.Debug -j8 debug/Base_def.o
    g++ -c -fno-keep-inline-dllexport -Wa,-mbig-obj -g -Wall -W -Wextra -fexceptions -mthreads -DUNICODE -D_UNICODE -DWIN32 -DMINGW_HAS_SECURE_API=1 -DQT_DEPRECATED_WARNINGS -DQT_QML_DEBUG -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DQT_NEEDS_QMAIN -I../Orientation -I. -I../../../../includes/date-master/include/date -ID:/Qt/App/5.13.0/mingw73_64/include -ID:/Qt/App/5.13.0/mingw73_64/include/QtWidgets -ID:/Qt/App/5.13.0/mingw73_64/include/QtGui -ID:/Qt/App/5.13.0/mingw73_64/include/QtANGLE -ID:/Qt/App/5.13.0/mingw73_64/include/QtCore -Idebug -I. -I\include -ID:/Qt/App/5.13.0/mingw73_64/mkspecs/win32-g++ -o debug/Base_def.o ../Orientation/Base_def.cpp
    ../Orientation/Base_def.cpp:8:29: error: expected ';' before ',' token
    Test<T>::U<_Vb-1,d>+2;
    ^
    ../Orientation/Base_def.cpp: In function 'int main()':
    ../Orientation/Base_def.cpp:18:16: warning: unused variable 'testDef' [-Wunused-variable]
    Test<test> testDef;
    ^~~~~~~
    mingw32-make: *** [Makefile.Debug:292: debug/Base_def.o] Error 1
    07:44:13: Le processus "D:\Qt\App\Tools\mingw730_64\bin\mingw32-make.exe" s'est terminé avec le code 2.
    Erreur lors de la compilation/déploiement du projet Orientation (kit : Desktop Qt 5.13.0 MinGW 64-bit)
    When executing step "Make"
    07:44:13: Temps écoulé : 00:01.

    Deuxième question : Maintenant je remets les commentaires et j'obtiens la suite.
    Ci après la sortie du compilo :
    07:29:36: Exécution des étapes pour le projet Orientation...
    07:29:36: Configuration inchangée, étape qmake sautée.
    07:29:36: Débute : "D:\Qt\App\Tools\mingw730_64\bin\mingw32-make.exe" -f Makefile.Debug -j8 debug/Base_def.o
    g++ -c -fno-keep-inline-dllexport -Wa,-mbig-obj -g -Wall -W -Wextra -fexceptions -mthreads -DUNICODE -D_UNICODE -DWIN32 -DMINGW_HAS_SECURE_API=1 -DQT_DEPRECATED_WARNINGS -DQT_QML_DEBUG -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DQT_NEEDS_QMAIN -I../Orientation -I. -I../../../../includes/date-master/include/date -ID:/Qt/App/5.13.0/mingw73_64/include -ID:/Qt/App/5.13.0/mingw73_64/include/QtWidgets -ID:/Qt/App/5.13.0/mingw73_64/include/QtGui -ID:/Qt/App/5.13.0/mingw73_64/include/QtANGLE -ID:/Qt/App/5.13.0/mingw73_64/include/QtCore -Idebug -I. -I\include -ID:/Qt/App/5.13.0/mingw73_64/mkspecs/win32-g++ -o debug/Base_def.o ../Orientation/Base_def.cpp
    ../Orientation/Base_def.cpp:8:26: error: 'U' was not declared in this scope
    /*Test<T>::*/U<_Vb-1,d>+2;
    ^
    ../Orientation/Base_def.cpp:13:33: error: duplicate initialization of 'Test::U<0, p>'
    constexpr unsigned Test/*<T>*/::U<0,p> = 5;
    ^~~~~~
    ../Orientation/Base_def.cpp:13:33: error: got 1 template parameters for 'constexpr const unsigned int Test::U<_Vb, d>'
    ../Orientation/Base_def.cpp:13:33: error: but 2 required
    ../Orientation/Base_def.cpp: In function 'int main()':
    ../Orientation/Base_def.cpp:18:20: warning: unused variable 'testDef' [-Wunused-variable]
    Test/*<test>*/ testDef;
    ^~~~~~~
    mingw32-make: *** [Makefile.Debug:292: debug/Base_def.o] Error 1
    07:29:37: Le processus "D:\Qt\App\Tools\mingw730_64\bin\mingw32-make.exe" s'est terminé avec le code 2.
    Erreur lors de la compilation/déploiement du projet Orientation (kit : Desktop Qt 5.13.0 MinGW 64-bit)
    When executing step "Make"
    07:29:37: Temps écoulé : 00:01.
    J'en déduis qu'on ne peut déclarer de variable récursivement dans ce cas là (il me dit que U n'existe pas). Là j'ai un peu du mal, car je souhaite créer une forme de liste de valeurs liées entre elles de cette manière. Une possibilité de contourner cela (il faut que ce soit constexpr car l'objectif est d'utiliser les variables obtenues dans des déclarations template)?
    Cordialement,
    Marc

  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,
    Si j'ai bien compris, tu voudrais avoir des expressions constantes de manière à associer les valeurs
    • 0 --> 5
    • 1 --> 7
    • ...
    • 10 -->25

    Dans un premier temps, je te proposerais de travailler "simplement" avec des valeurs de type bien défini, sous une forme proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    namespace Details {
    template <unsigned V>
    struct Recursive_impl {
    	static constexpr unsigned result = Recursive_impl<V-1>::result + 2;
    };
    template <>
    struct Recursive_impl<0> {
    	static constexpr unsigned result = 5;
    };
     
    } //namespace Details
    J'ai placé ma structure (dont tu peux changer le nom à ta guise ) dans un espace de noms spécifique, parce que cela ne sera jamais qu'un "détail d'implémentation" du reste de ton problème

    La deuxième définition (template <> struct Recursive_impl<0>) est une spécialisation totale de la structure prévue pour mettre fin à la récursion, en définissant une valeur bien spécifique (que tu peux modifier à ta guise) pour le résultat

    Nous pouvons assez facilement vérifier que ce genre de structure fonctionne avec un code aussi simple que
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    int main() {
    	auto result = Details::Recursive_impl<1>::result ;
    	std::cout << result << "\n";
    }
    L'étape suivante sera de s'assurer que nous ayons bel et bien à faire à des valeurs susceptibles d'être considérées comme des valeur numérique entières non signées.
    Nous pourrions donc créer un "convertisseur" sous une forme proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    namespace Details{
    template <typename T>
    struct Converter_impl {
    	static_assert(std::is_integral<T>::value || std::is_enum<T>::value,
    		"T template parameter should be an integral or an enum type");
    	/* parce qu'il est toujours sympa de connaitre le type*/
    	using value_t = unsigned;
    	template<T V> 
    	static constexpr value_t result = Recursive_impl<static_cast<unsigned>(V)>::result;
    };
    } // namespace Details
    encore une fois, je l'ai placé dans l'espace de noms Details parce que ce sera le plus souvent un détail d'implémentation.

    Le static_assert est là pour s'assurer que nous ayons bel et bien à faire à un type qui pourra être aisément converti en unsigned int. Je l'ai défini de manière très restreinte pour éviter les problèmes de conversions et de perte de précision (par exemple, avec les types réels, tels que float ou double) ... Tu peux, bien sur, adapter cette assertion à tes propres besoins

    Ce qui peut d'avantage te surprendre, c'est que j'ai fait appel à static_cast lors de l'appel à Recursive_impl. Je l'ai placé pour éviter les problèmes liés à l'utilisation de valeurs énumérées issues d'énumérations fortement typées. Sans lui, un code proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    int main() {
    	enum class Test {
    		Debut,
    		Fin
    	};
    	auto result = Details::Converter_impl<Test>::result<Test::Fin> ;
    	std::cout << result << "\n";
    }
    (qui permet au passage de m'assureer que la conversion fonctionne) m'aurait normalement envoyé sur les roses sous prétexte que le compilateur ne peut pas convertir Test::Fin en valeur non signée .

    Est ce que cela correspond à peu près à tes besoins ?
    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
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 151
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 151
    Billets dans le blog
    4
    Par défaut
    Le code compile sous VS2017, avec ou sans les commentaires.
    Les variables templates sont une nouveauté C++14, es-tu sûr de compiler avec cette version ?
    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
    #include <iostream>
    template <class T>
    struct Test {
    	template <unsigned _Vb, typename d = void>
    	static constexpr unsigned U =
    		Test<T>::U<_Vb - 1, d>+2;
    };
     
    template< class T>
    template <typename p>
    constexpr unsigned Test<T>::U<0, p> = 5;
     
    int main()
    {
    	enum class test { Debut, A = Debut, B, Fin };
    	std::cout << Test<test>::U<3>;
    }
    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
    #include <iostream>
    //template <class T>
    struct Test {
    	template <unsigned _Vb, typename d = void>
    	static constexpr unsigned U =
    		/*Test<T>::*/U<_Vb - 1, d>+2;
    };
     
    //template< class T>
    template <typename p>
    constexpr unsigned Test/*<T>*/::U<0, p> = 5;
     
    int main()
    {
    	std::cout << Test::U<3>;
    }
    Affichent 11.
    Si j'y passe une valeur élevée par contre, il ne sait pas faire à cause de la récursivité trop grande.

    Ensuite, je comprends pas du tout où tu veux en venir : tu crées une structure template où tu n'utilises jamais le type template ?
    static constexpr unsigned U = /*Test<T>::*/U<_Vb-1,d>+2; mettre un template avant Test pourrait aider le compilateur à s'y retrouver.
    Perso je préfère une déclaration de ce type
    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
    #include <iostream>
    template <unsigned _Vb, typename d = void>
    struct Test {
    	template <unsigned V, typename D>
    	struct Internal
    	{
    		static constexpr unsigned U = Internal<V - 1, D>::U + 2;
    	};
    	template<typename D>
    	struct Internal<0, D>
    	{
    		static constexpr unsigned U = 5;
    	};
    	static constexpr unsigned U = Internal<_Vb, d>::U;
    };
     
    int main()
    {
    	std::cout << Test<3>::U;
    }
    Ce code fait la même chose (le template est déplacé de la variable à la structure, si ça dérange tu peux aussi créer une structure intermédiaire interne pour y mettre le template) et est compatible C++11.
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  4. #4
    Membre confirmé
    Profil pro
    Inscrit en
    Mai 2007
    Messages
    159
    Détails du profil
    Informations personnelles :
    Localisation : France, Moselle (Lorraine)

    Informations forums :
    Inscription : Mai 2007
    Messages : 159
    Par défaut
    Bonjour, et merci les amis

    @kola01 Oui cela correspond bien. Ta solution me convient d'autant qu'elle va me permettre en l'étendant un peu de résoudre d'autres détails d'implémentation du même style.
    @bousk En fait, j'ai activé C++2a. Cela m'a inspiré une série de tests dans ces conditions, en activant différentes versions de C++ : mon compilateur a bien un souci avec la déclaration telle que je la fais : Elle génère systématiquement une erreur. Soit c'est "erreur : expected ';' before ',' token static constexpr unsigned U = Test<T>::U<_Vb-1ici,d>+2;", soit c'est erreur interne du compilateur.
    Dans tous les cas je crois mon code juste et il y trouve une erreur.
    Je pense que je vais remonter un bug, il va juste falloir que j'essaie avec la dernière version de MinGW avant .
    L'autre 'anomalie' : j'ai même mis des valeurs aberrantes à ma config (faute de frappe une fois), sans que ni qmake ni le compilo n'y trouvent à redire...
    Merci encore pour votre aide

    Cordialement,
    Marc

  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
    Tu peux faire des tests sur différents compilateurs et versions avec https://wandbox.org/ et/ou https://godbolt.org/

    Même avec la dernière version, gcc n'arrive pas à résoudre la récursivité.

  6. #6
    Membre confirmé
    Profil pro
    Inscrit en
    Mai 2007
    Messages
    159
    Détails du profil
    Informations personnelles :
    Localisation : France, Moselle (Lorraine)

    Informations forums :
    Inscription : Mai 2007
    Messages : 159
    Par défaut
    Bonjour,

    @Bousk (j'ai relu ton post ) :
    Ensuite, je comprends pas du tout où tu veux en venir : tu crées une structure template où tu n'utilises jamais le type template ?
    En fait le secret de cette structure c'est la spécialisation de l'interruption de la récursivité. Celle là est liée à mon type template.
    J'en ai créé une par une spécialisation partielle qui correspond à une 'valeur par défaut', mais on pourra changer cela pour tout paramètre du template Test.
    On pourra écrire
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    template <>
    constexpr unsigned Test<uneClasse>::U<0, p> = 0; // donnera 6 pour Test<uneClasse>::U<3>
    template <>
    constexpr unsigned Test<uneAutreClasse>::U<3, p> = 8; // donnera 14 pour Test<uneAutreClasse>::U<6> et 4 pour Test<uneAutreClasse>::U<2>
    Si on retire le '+2' à l'expression, on obtient un bornage par défaut d'intervalles si on spécialise plusieurs interruptions de récursivité pour le même type template.
    Si j'y passe une valeur élevée par contre, il ne sait pas faire à cause de la récursivité trop grande.
    C'est noté. Je n'y avais pas pensé. Cela dit, dans mon cas ce n'est pas grave, je n'ai pas prévu de faire cela pour des grands intervalles.

    @jo_link_noir Merci pour tes liens. Je vais y faire des tests.
    Même avec la dernière version, gcc n'arrive pas à résoudre la récursivité.
    Même sous linux? (j'ai trouvé un post citant la même erreur interne qui se produisait avec Mingw/gcc et pas Linux/gcc, bien que pas avec le même code)

    Bon je vais signaler un bug, car pour ce que j'en comprends mon code est juste (je n'y fais pas de chose interdite à ma connaissance) et le compilateur signale une erreur sans préciser laquelle (déjà rien que ça le justifie je pense). Sans compter que ça compile en VS2017.

    Je vous remercie tous pour vos interventions !
    @bientôt,
    Marc

  7. #7
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 151
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 151
    Billets dans le blog
    4
    Par défaut
    Citation Envoyé par Teaniel Voir le message
    En fait le secret de cette structure c'est la spécialisation de l'interruption de la récursivité. Celle là est liée à mon type template.
    J'en ai créé une par une spécialisation partielle qui correspond à une 'valeur par défaut', mais on pourra changer cela pour tout paramètre du template Test.
    Et pourquoi ne pas juste créer une constante et mettre le type dedans également ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    template <class T, unsigned _Vb, typename d = void>
    static constexpr unsigned U = U<T, _Vb - 1, d>+2;
    template <class T, typename p>
    constexpr unsigned U<T, 0, p> = 5;
     
    #include <iostream>
    int main()
    {
        std::cout << U<void, 3> << std::endl;
        return 0;
    }
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

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

Discussions similaires

  1. Réponses: 6
    Dernier message: 04/06/2010, 11h37
  2. Erreur interne compilateur visual basic
    Par freerider74 dans le forum Visual Studio
    Réponses: 0
    Dernier message: 15/03/2010, 09h26
  3. Réponses: 26
    Dernier message: 28/01/2010, 12h53
  4. Fonction template, erreur interne du compilateur
    Par Emiler dans le forum Langage
    Réponses: 9
    Dernier message: 08/04/2009, 12h14
  5. [BOOST] erreur interne du compilateur
    Par venomelektro dans le forum Bibliothèques
    Réponses: 1
    Dernier message: 15/04/2006, 18h08

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