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 :

template dans header mais erreur au link


Sujet :

Langage C++

  1. #1
    Membre expérimenté Avatar de ctxnop
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juillet 2007
    Messages
    858
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Morbihan (Bretagne)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2007
    Messages : 858
    Points : 1 732
    Points
    1 732
    Par défaut template dans header mais erreur au link
    Bonjour,
    Je cherche à me faire un manipulateur de console dans le but de pouvoir écrire : std::cout << con::red() << "message qui apparait en rouge" << std::endl;
    Idéalement j'aurais bien aimé que red se passe des () (à l'image du endl). Mais bon, je ne veut pas faire des defines ou des instances globales.
    Du coup je suis parti sur des template et des typedef :

    Code c++ : 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
    #pragma once
     
    #include <iostream>
     
    #if WIN32
    #include <windows.h>
    #else
    #include <sstream>
    #endif
     
    namespace con {
     
    	/**
             * @brief Représente une manipulateur de console.
             */
    	template <unsigned int color, bool bold, bool blink, bool reset>
    	class _con
    	{
    	public:
    		/**
                     * @brief Construit un nouveau manipulateur de console.
                     */
    		_con() { }
     
    		/**
                     * @brief Permet de modifier les attributs de la console std::cout.
                     * @param[in] o La console à modifier (std::cout).
                     * @param[in] c La couleur à mettre.
                     * @return Le flux modifié (std::cout).
                     */
    		friend std::ostream& operator<<(std::ostream& o, const _con<color, bold, blink, reset>& c);
    	};
     
    #if WIN32
    	typedef _con<0, false, false, false>													black;
    	typedef _con<FOREGROUND_BLUE, false, false, false>										darkblue;
    	typedef _con<FOREGROUND_GREEN, false, false, false>										darkgreen;
    	typedef _con<FOREGROUND_BLUE | FOREGROUND_GREEN, false, false, false>					darkcyan;
    	typedef _con<FOREGROUND_RED, false, false, false>										darkred;
    	typedef _con<FOREGROUND_BLUE | FOREGROUND_RED, false, false, false>						darkmagenta;
    	typedef _con<FOREGROUND_GREEN | FOREGROUND_RED, false, false, false>					darkyellow;
    	typedef _con<FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED, false, false, false>	gray;
     
    	typedef _con<0, true, false, false>														darkgray;
    	typedef _con<FOREGROUND_BLUE, true, false, false>										blue;
    	typedef _con<FOREGROUND_GREEN, true, false, false>										green;
    	typedef _con<FOREGROUND_BLUE | FOREGROUND_GREEN, true, false, false>					cyan;
    	typedef _con<FOREGROUND_RED, true, false, false>										red;
    	typedef _con<FOREGROUND_BLUE | FOREGROUND_RED, true, false, false>						magenta;
    	typedef _con<FOREGROUND_GREEN | FOREGROUND_RED, true, false, false>						yellow;
    	typedef _con<FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED, true, false, false>	white;
     
    	typedef _con<0, false, false, false>													bg_black;
    	typedef _con<BACKGROUND_BLUE, false, false, false>										bg_darkblue;
    	typedef _con<BACKGROUND_GREEN, false, false, false>										bg_darkgreen;
    	typedef _con<BACKGROUND_BLUE | BACKGROUND_GREEN, false, false, false>					bg_darkcyan;
    	typedef _con<BACKGROUND_RED, false, false, false>										bg_darkred;
    	typedef _con<BACKGROUND_BLUE | BACKGROUND_RED, false, false, false>						bg_darkmagenta;
    	typedef _con<BACKGROUND_GREEN | BACKGROUND_RED, false, false, false>					bg_darkyellow;
    	typedef _con<BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED, false, false, false>	bg_gray;
     
    	typedef _con<0, true, false, false>														bg_darkgray;
    	typedef _con<BACKGROUND_BLUE, true, false, false>										bg_blue;
    	typedef _con<BACKGROUND_GREEN, true, false, false>										bg_green;
    	typedef _con<BACKGROUND_BLUE | BACKGROUND_GREEN, true, false, false>					bg_cyan;
    	typedef _con<BACKGROUND_RED, true, false, false>										bg_red;
    	typedef _con<BACKGROUND_BLUE | BACKGROUND_RED, true, false, false>						bg_magenta;
    	typedef _con<BACKGROUND_GREEN | BACKGROUND_RED, true, false, false>						bg_yellow;
    	typedef _con<BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED, true, false, false>	bg_white;
     
    	//typedef _con<0x80000000, false, false, true> reset_default;
    #else
    #endif
     
    	/**
             * @brief Permet de modifier les attributs de la console std::cout.
             * @param[in] o La console à modifier (std::cout).
             * @param[in] c La couleur à mettre.
             * @return Le flux modifié (std::cout).
             */
    	template <unsigned int color, bool bold, bool blink, bool reset>
    	std::ostream& operator<<(std::ostream& o, const _con<color, bold, blink, reset>& c)
    	{
    #if WIN32
    		HANDLE hout = ::GetStdHandle(STD_OUTPUT_HANDLE);
    		WORD value = (bold ? ((color > (FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED)) ? BACKGROUND_INTENSITY | FOREGROUND_INTENSITY) : color)
    		::SetConsoleTextAttribute(hout, value);
    #else
    #endif
    		return o;
    	}
     
    }

    Il s'agit d'un premier essai qui ne gère que Windows pour le moment. L'argument blink sera utilisé sous les terminaux unix qui le supportent. Idem pour le reset (que j'essaierai de gérer aussi sous Windows mais j'ai cru comprendre qu'il fallait aller lire dans la base de registre pour avoir la valeur à utiliser...)

    Évidemment tout ce code est dans un header, et tout compile. Mais ça ne link pas :
    Code text : Sélectionner tout - Visualiser dans une fenêtre à part
    string-test.obj : error LNK2019: symbole externe non résolu "class std::basic_ostream<char,struct std::char_traits<char> > & __cdecl con::operator<<(class std::basic_ostream<char,struct std::char_traits<char> > &,class con::_con<4,1,0,0> const &)" (??6con@@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@std@@AAV34@ABV?$_con@$03$00$0A@$0A@@012@@Z) référencé dans la fonction "public: void __thiscall npp_sys_txt_string::console_color::test_method(void)" (?test_method@console_color@npp_sys_txt_string@@QAEXXZ)

    Le code qui utilise (et donc provoque le problème de link):
    Code c++ : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    #include <boost/test/unit_test.hpp>
     
    #include "console.hpp"
     
    BOOST_AUTO_TEST_SUITE( npp_sys_txt_string )
     
    	BOOST_AUTO_TEST_CASE( console_color )
    	{
    		std::cout << con::red() << "bouuhh" << std::endl;
    	}
     
    BOOST_AUTO_TEST_SUITE_END()

    Je ne m'attendais pas spécialement à ce que ça tourne parfaitement du premier coup, mais une erreur de link dans un template ?! je sèche un peu là...
    Quelqu'un à une idée ?

    edit : Ah oui, au cas où ça aiderait : je suis sous Visual Studio 2012 ultimate update 4.

  2. #2
    Membre expérimenté Avatar de ctxnop
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juillet 2007
    Messages
    858
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Morbihan (Bretagne)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2007
    Messages : 858
    Points : 1 732
    Points
    1 732
    Par défaut
    Bon, je n'ai pas bien compris le pourquoi ça plante au link, mais après avoir tenté avec gcc sur linux, j'ai vu apparaitre un warning qui m'a mis sur la piste. Une petite recherche et je suis tombé sur http://en.wikibooks.org/wiki/More_C%...ng_New_Friends.

    La solution est donc d'implémenter l'opérateur dans la classe. De cette façon l'implémentation est un template de fonction friend.

    Il semble que ça marche sous Windows et Linux.

    Au cas où ça intéresserait quelqu'un, voici le code corrigé et qui semble fonctionnel (je n'ai pas testé toutes les couleurs, et pas du tout les couleurs de fond) :
    Code c++ : 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
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
     
    #ifndef NPP_SYS_CONSOLE_HPP
    #define NPP_SYS_CONSOLE_HPP
     
    #include <iostream>
     
    #if WIN32
    #include <windows.h>
    #else
    #include <sstream>
    #endif
     
    namespace con {
     
    	/**
             * @brief Représente une manipulateur de console.
             */
    	template <unsigned int color, bool bold, bool blink, bool reset>
    	class con_manipulator
    	{
    	public:
    		/**
                     * @brief Construit un nouveau manipulateur de console.
                     */
    		con_manipulator() { }
     
    		/**
                     * @brief Permet de modifier les attributs de la console std::cout.
                     * @param[in] o La console à modifier (std::cout).
                     * @param[in] c La couleur à mettre.
                     * @return Le flux modifié (std::cout).
                     */
    		friend std::ostream& operator<<(std::ostream& o, const con_manipulator<color, bold, blink, reset>& c)
    		{
    #if WIN32
    		HANDLE hout = ::GetStdHandle(STD_OUTPUT_HANDLE);
    		unsigned int col = color;
    		if(bold)
    		{
    			if(col & (FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED)) col |= FOREGROUND_INTENSITY;
    			if(col & (BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED)) col |= BACKGROUND_INTENSITY;
    		}
    		::SetConsoleTextAttribute(hout, col);
    #else
    		std::stringstream ss;
    		ss << "\033[" << (bold ? "1" : "0") << ";" << color << "m";
    		o << ss.str();
    #endif
    		return o;
    		}
    	};
     
    #if WIN32
    	typedef con_manipulator<0, false, false, false>								black;
    	typedef con_manipulator<FOREGROUND_BLUE, false, false, false>						darkblue;
    	typedef con_manipulator<FOREGROUND_GREEN, false, false, false>						darkgreen;
    	typedef con_manipulator<FOREGROUND_BLUE | FOREGROUND_GREEN, false, false, false>			darkcyan;
    	typedef con_manipulator<FOREGROUND_RED, false, false, false>						darkred;
    	typedef con_manipulator<FOREGROUND_BLUE | FOREGROUND_RED, false, false, false>			darkmagenta;
    	typedef con_manipulator<FOREGROUND_GREEN | FOREGROUND_RED, false, false, false>			darkyellow;
    	typedef con_manipulator<FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED, false, false, false>	gray;
     
    	typedef con_manipulator<0, true, false, false>								darkgray;
    	typedef con_manipulator<FOREGROUND_BLUE, true, false, false>						blue;
    	typedef con_manipulator<FOREGROUND_GREEN, true, false, false>						green;
    	typedef con_manipulator<FOREGROUND_BLUE | FOREGROUND_GREEN, true, false, false>			cyan;
    	typedef con_manipulator<FOREGROUND_RED, true, false, false>						red;
    	typedef con_manipulator<FOREGROUND_BLUE | FOREGROUND_RED, true, false, false>			magenta;
    	typedef con_manipulator<FOREGROUND_GREEN | FOREGROUND_RED, true, false, false>			yellow;
    	typedef con_manipulator<FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED, true, false, false>	white;
     
    	typedef con_manipulator<0, false, false, false>														bg_black;
    	typedef con_manipulator<BACKGROUND_BLUE, false, false, false>						bg_darkblue;
    	typedef con_manipulator<BACKGROUND_GREEN, false, false, false>						bg_darkgreen;
    	typedef con_manipulator<BACKGROUND_BLUE | BACKGROUND_GREEN, false, false, false>			bg_darkcyan;
    	typedef con_manipulator<BACKGROUND_RED, false, false, false>						bg_darkred;
    	typedef con_manipulator<BACKGROUND_BLUE | BACKGROUND_RED, false, false, false>			bg_darkmagenta;
    	typedef con_manipulator<BACKGROUND_GREEN | BACKGROUND_RED, false, false, false>			bg_darkyellow;
    	typedef con_manipulator<BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED, false, false, false>	bg_gray;
     
    	typedef con_manipulator<0, true, false, false>								bg_darkgray;
    	typedef con_manipulator<BACKGROUND_BLUE, true, false, false>						bg_blue;
    	typedef con_manipulator<BACKGROUND_GREEN, true, false, false>						bg_green;
    	typedef con_manipulator<BACKGROUND_BLUE | BACKGROUND_GREEN, true, false, false>			bg_cyan;
    	typedef con_manipulator<BACKGROUND_RED, true, false, false>						bg_red;
    	typedef con_manipulator<BACKGROUND_BLUE | BACKGROUND_RED, true, false, false>			bg_magenta;
    	typedef con_manipulator<BACKGROUND_GREEN | BACKGROUND_RED, true, false, false>			bg_yellow;
    	typedef con_manipulator<BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED, true, false, false>	bg_white;
    #else
    	typedef con_manipulator<30, false, false, false>	black;
    	typedef con_manipulator<31, false, false, false>	darkred;
    	typedef con_manipulator<32, false, false, false>	darkgreen;
    	typedef con_manipulator<33, false, false, false>	darkyellow;
    	typedef con_manipulator<34, false, false, false>	darkblue;
    	typedef con_manipulator<35, false, false, false>	darkmagenta;
    	typedef con_manipulator<36, false, false, false>	darkcyan;
    	typedef con_manipulator<37, false, false, false>	gray;
     
    	typedef con_manipulator<30, true, false, false>	darkgray;
    	typedef con_manipulator<31, true, false, false>	red;
    	typedef con_manipulator<32, true, false, false>	green;
    	typedef con_manipulator<33, true, false, false>	yellow;
    	typedef con_manipulator<34, true, false, false>	blue;
    	typedef con_manipulator<35, true, false, false>	magenta;
    	typedef con_manipulator<36, true, false, false>	cyan;
    	typedef con_manipulator<37, true, false, false>	white;
     
    	typedef con_manipulator<40, false, false, false>	bg_black;
    	typedef con_manipulator<41, false, false, false>	bg_darkred;
    	typedef con_manipulator<42, false, false, false>	bg_darkgreen;
    	typedef con_manipulator<43, false, false, false>	bg_darkyellow;
    	typedef con_manipulator<44, false, false, false>	bg_darkblue;
    	typedef con_manipulator<45, false, false, false>	bg_darkmagenta;
    	typedef con_manipulator<46, false, false, false>	bg_darkcyan;
    	typedef con_manipulator<47, false, false, false>	bg_gray;
     
    	typedef con_manipulator<40, true, false, false>	bg_darkgray;
    	typedef con_manipulator<41, true, false, false>	bg_red;
    	typedef con_manipulator<42, true, false, false>	bg_green;
    	typedef con_manipulator<43, true, false, false>	bg_yellow;
    	typedef con_manipulator<44, true, false, false>	bg_blue;
    	typedef con_manipulator<45, true, false, false>	bg_magenta;
    	typedef con_manipulator<46, true, false, false>	bg_cyan;
    	typedef con_manipulator<47, true, false, false>	bg_white;
    #endif
     
    }
     
    #endif // NPP_SYS_CONSOLE_HPP

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

Discussions similaires

  1. Réponses: 4
    Dernier message: 22/11/2010, 14h15
  2. Erreur de link avec les templates
    Par suiss007 dans le forum C++
    Réponses: 6
    Dernier message: 04/01/2007, 11h09
  3. template et erreur de link
    Par Willand dans le forum Langage
    Réponses: 12
    Dernier message: 05/12/2006, 21h19
  4. Réponses: 15
    Dernier message: 21/08/2006, 01h41
  5. __declspec(dllexport) dans mon fichier header mais...?
    Par Jasmine dans le forum Autres éditeurs
    Réponses: 1
    Dernier message: 03/03/2004, 18h00

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