Bonjour, je me mets au C++ (après avoir bcp fait de C). J'arrive à exporter une classe mais j'ai un soucis dans la surcharge de l'opérateur <<.

A l'exécution, j'obtiens l'erreur suivante :

error LNK2019: unresolved external symbol "class std::basic_ostream<char,struct std::char_traits<char> > & __cdecl operator<<(class std::basic_ostream<char,struct std::char_traits<char> > &,class DataExpNSF const &)" (??6@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@std@@AAV01@ABVDataExpNSF@@@Z) referenced in function "void __cdecl testTSSNSF(char const *,struct _iobuf *)" (?testTSSNSF@@YAXPBDPAU_iobuf@@@Z)
Voici mon code :

qq macros (chopée du net) :

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
 
/* macro pour exporter (importer) un std::vector dans une (d'une) dll */
#define IMPORTEXPORT_STL_VECTOR( dllmacro, vectype ) \
  template class dllmacro std::allocator< vectype >; \
  template class dllmacro std::vector<vectype, \
    std::allocator< vectype > >
 
/* macro pour exporter un std::vector dans une dll */
#define EXPORT_STL_VECTOR( vectype ) IMPORTEXPORT_STL_VECTOR(__declspec(dllexport), vectype )
 
/* macro pour importer un std::vector d'une dll */
#define IMPORT_STL_VECTOR( vectype ) IMPORTEXPORT_STL_VECTOR(__declspec(dllimport), vectype )
 
/* macro pour exporter un std::vector<double> dans une dll */
#define EXPORT_STL_VECTOR_DOUBLE EXPORT_STL_VECTOR(double)
 
#ifdef BIBStructures_EXPORTS
#define BIBStructures_API __declspec(dllexport)
#else
#define BIBStructures_API __declspec(dllimport)
#endif
Mon .hpp

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
 
EXPORT_STL_VECTOR_DOUBLE;
 
class BIBStructures_API DataExpNSF
{
  private :
 
    int               _titre;    /* titre de l'eprouvette */
	double            _pretens;  /* pretension [N]        */
	vector < double > _t;        /* temps [s]             */
	vector < double > _traverse; /* traverse normee [mm]  */
	vector < double > _F;        /* force standard [N]    */
	vector < double > _allong;   /* allongement [%]       */
	vector < double > _T;        /* temperature [deg C]   */
 
  public :
 
  /* default constructor */
  DataExpNSF();
 
  /* constructor */
  DataExpNSF(int titre,double pretens,const vector < double > & t,const vector < double > & traverse,
	  const vector < double > & F,const vector < double > & allong,const vector < double > & T);
 
  /* destructor */
  ~DataExpNSF();
 
  /* renvoie la valeur du titre de l'eprouvette */
  int getTitre(void) const;
 
  /* fixe la valeur du titre de l'eprouvette */
  void setTitre(int titre);
 
  /* renvoie la valeur de la pretension (en N) */
  double getPretension(void) const;
 
  /* fixe une valeur a la pretension */
  void setPretension(double pretens);
 
  /* retourne le vector contenant les temps [s] */
  const vector<double> & getTemps(void) const;
 
  /* retourne le vector contenant les traverses normees [mm] */
  const vector<double> & getTraverse(void) const;
 
  /* retourne le vector contenant les forces standard [N] */
  const vector<double> & getForce(void) const;
 
  /* retourne le vector contenant les allongements [%] */
  const vector<double> & getAllong(void) const;
 
  /* retourne le vector contenant les temperatures [deg C] */
  const vector<double> & getTemperature(void) const;
 
  /* true si les vectors _t, _traverse, _F, _allong et _T sont de meme dimension
     false sinon
   */
  bool checkDimensions(void) const;
 
  /* ajoute un element a la fin de chaque vector */
  void pushBackSample(double t,double traverse,double F,double allong,double T);
 
  /* lecture d'un fichier de mesure et stockage des donnees experimentales dans la classe DataExpNSF
 
     renvoie :
      0 : aucune erreur
     -1 : echec lors de l'ouverture du fichier de mesure
      1 : echec lors de la lecture de la valeur du titre de l'eprouvette
      2 : echec lors de la lecture de la valeur de la pretension
	  3 : echec lors de la lecture du nom des colonnes
	  4 : echec lors de la lecture des unites des colonnes
	  5 : echec lors de la lecture des donnees experimentales
   */
  int readFile(const string & filename);
 
  /* surcharge de l'operateur << */
  friend std::ostream & operator<<(std::ostream & os, const DataExpNSF & d);
};
et voici mon .cpp

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
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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
 
/* default constructor */
DataExpNSF::DataExpNSF()
{
  _titre = -1; _pretens = -1.;
}
 
/* constructor */
DataExpNSF::DataExpNSF(int titre, double pretens, const std::vector<double> & t, 
					   const std::vector<double> & traverse, const std::vector<double> & F, 
					   const std::vector<double> & allong, const std::vector<double> & T)
{
  _titre    = titre;
  _pretens  = pretens;
  _t        = t;
  _traverse = traverse;
  _F        = F;
  _allong   = allong;
  _T        = T;
}
 
/* destructor */
DataExpNSF::~DataExpNSF()
{
  _titre = -1; _pretens = -1.;
  _t.clear(); _traverse.clear(); _F.clear(); _allong.clear(); _T.clear();
}
 
/* getTitre :
   renvoie la valeur du titre de l'eprouvette
 */
inline int DataExpNSF::getTitre(void) const
{
  return _titre;
}
 
/* setTitre :
   fixe la valeur du titre de l'eprouvette
 */
inline void DataExpNSF::setTitre(int titre)
{
  _titre = titre;
}
 
/* getPretension :
   renvoie la valeur de la pretension (en N)
 */
inline double DataExpNSF::getPretension(void) const
{
  return _pretens;
}
 
/* setPretension :
   fixe une valeur a la pretension
 */
inline void DataExpNSF::setPretension(double pretens)
{
  _pretens = pretens;
}
 
/* getTemps :
   retourne le vector contenant les temps [s]
 */
inline const vector<double> & DataExpNSF::getTemps(void) const
{
  return _t;
}
 
/* getTraverse :
   retourne le vector contenant les tracerses normees [mm]
 */
inline const vector<double> & DataExpNSF::getTraverse(void) const
{
  return _traverse;
}
 
/* getForce :
   retourne le vector contenant les forces standard [N]
 */
inline const vector<double> & DataExpNSF::getForce(void) const
{
  return _F;
}
 
/* getAllong :
   retourne le vector contenant les allongements [%]
 */
inline const vector<double> & DataExpNSF::getAllong(void) const
{
  return _allong;
}
 
/* getTemperature :
   retourne le vector contenant les temperatures [deg C]
 */
inline const vector<double> & DataExpNSF::getTemperature(void) const
{
  return _T;
}
 
/* checkDimensions :
   true si les vectors _t, _traverse, _F, _allong et _T sont de meme dimension
   false sinon
 */
inline bool DataExpNSF::checkDimensions(void) const
{
  size_t n = _t.size();
  if( (_traverse.size() == n) && (_F.size() == n) && (_allong.size() == n) && (_T.size() == n) )
    return true;
  else
    return false;
}
 
/* pushBackSample : 
   ajoute un element a la fin de chaque vector
 */
void DataExpNSF::pushBackSample(double t,double traverse,double F,double allong,double T)
{
  _t.push_back(t); _traverse.push_back(traverse); _F.push_back(F); _allong.push_back(allong);
  _T.push_back(T);
}
 
std::ostream & operator<<(std::ostream & os, const DataExpNSF & d)
{
  bool test = d.checkDimensions();
  if(test == true)
  {
    const vector<double> t        = d.getTemps();
    const vector<double> traverse = d.getTraverse();
    const vector<double> F        = d.getForce();
    const vector<double> allong   = d.getAllong();
    const vector<double> T        = d.getTemperature();
	size_t i, n = t.size();
 
    os << "titre = " << d.getTitre() << std::endl;
    os << "pretension = " << d.getPretension() << " N" << std::endl << std::endl;
    os << "1e colonne : temps [s]" << std::endl;
    os << "2e colonne : traverse normee [mm]" << std::endl;
    os << "3e colonne : force [N]" << std::endl;
    os << "4e colonne : allongement [%]" << std::endl;
    os << "5e colonne : temperature [deg C]" << std::endl << std::endl;
 
    for(i = 0 ; i < n ; i++)
	{
      os << t[i] << ' ' << traverse[i] << ' ' << F[i] << ' ' << allong[i] << ' ' << T[i] << std::endl;
	}
	os << std::endl;
  }
  else /* test == false */
  {
	std::cerr << "Erreur de dimension !!" << std::endl;
  }
 
  return os;
}
 
/* readFile :
   lecture d'un fichier de mesure et stockage des donnees experimentales dans la classe DataExpNSF
 
   renvoie :
    0 : aucune erreur
   -1 : echec lors de l'ouverture du fichier de mesure
    1 : echec lors de la lecture de la valeur du titre de l'eprouvette
    2 : echec lors de la lecture de la valeur de la pretension
	3 : echec lors de la lecture du nom des colonnes
	4 : echec lors de la lecture des unites des colonnes
	5 : echec lors de la lecture des donnees experimentales
 */
int DataExpNSF::readFile(const string & filename)
{
  /* ouverture du fichier en lecture */
  std::ifstream file( filename.c_str() );
 
  if(!file) /* echec a l'ouverture */
  {
    ERRORFOPEN(filename);
	return -1;
  }
  else
  {
    string line; /* variable contenant la ligne lue */
	int    flag_pretens, flag_titre, flag_colname, flag_colunite, ret, flag_reading;
	double t, traverse, F, allong, T, aux;
	size_t len;
	char   str[1024];
 
	/* nom des colonnes : il y a 2 possibilites */
	const string colname1 = "\"Temps d'essai\";\"Traverse normée\";\"Force standard\";\"Allong.\";\"Température\"";
	const string colname2 = "Temps d'essai	Traverse normée	Force standard	Allong.	Température";
 
	/* unite des colonnes : il y a 2 possibilites */
	const string colunite1 = "\"s\";\"mm\";\"N\";\"%\";\"°C\"";
	const string colunite2 = "s	mm	N	%	°C";
 
	/* intialisation des flags */
	flag_pretens = flag_titre = flag_colname = flag_colunite = flag_reading = 1;
 
	while ( std::getline( file, line ) ) /* lecture du fichier */
	{
	  /* lecture de la valeur de la pretension */
	  if(flag_pretens)_pretens = readPretension(flag_pretens,line);
 
	  /* lecture du titre de l'eprouvette */
	  if(flag_titre)_titre = readTitre(flag_titre,line);
 
	  /* lecture du nom et des unites des colonnes. On doit d'abord avoir le nom des colonnes
	     puis leurs unites
	   */
	  if(flag_colname && flag_colunite && ((line == colname1) || (line == colname2)) ) flag_colname = 0;
 
	  if(!flag_colname && flag_colunite && ((line == colunite1) || (line == colunite2)) ) flag_colunite = 0;
 
 
	  if( (flag_reading == 1) && !flag_colname && !flag_colunite )
	    flag_reading = 0;
	  else if(flag_reading == 0)
		  flag_reading = 2;
 
	  /* lecture des donnees experimentales */
	  if(flag_reading == 2)
	  {
	    len = line.copy(str,line.size(),0);
		str[len] = '\0';
 
		/* on remplace tous les ';' par des ' ' et tous les ',' par des '.'*/
		for(size_t i = 0 ; i < len ; i++)
		{
          if(str[i] == ';')
		    str[i] = ' ';
		  else if(str[i] == ',')
		    str[i] = '.';
		}
 
		/* on veut lire 5 colonnes. On fait expres d'en mettre 6 pour s'assurer qu'il y en
		   a exactement 5
	     */
		ret = sscanf(str,"%lf%lf%lf%lf%lf%lf",&t,&traverse,&F,&allong,&T,&aux);
		if(ret == 5)
		{
          /* stockage des donnees experimentales */
		  _t.push_back(t); _traverse.push_back(traverse); _F.push_back(F);
		  _allong.push_back(allong); _T.push_back(T);
		}
		else
		{
		  ERROR("reading error");
		  std::cerr << "ret = " << ret << std::endl;
		  std::cerr << "line = " << line << std::endl;
		  std::cerr << "length = " << line.size() << std::endl;
 
          return 5;
		}
	  } /* if(!flag_colname && !flag_colunite) */
 
	} /* while ( std::getline( file, line ) ) */
 
	file.close();
 
	/* retour des erreurs de lecture */
	if(_titre == -1) return 1;
	if(fabs(_pretens + 1) < EPS) return 2;
	if(flag_colname) return 3;
	if(flag_colunite) return 4;
 
	return 0;
 
  } /* else "if(!file)" */
}
En gros le problème est : comment exporter la fonction operator << ?

Merci d'avance