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.