Pensar en C++ (Volumen 1) - Grupo ARCO
Pensar en C++ (Volumen 1) - Grupo ARCO Pensar en C++ (Volumen 1) - Grupo ARCO
✐ ✐ ✐ “Volumen1” — 2012/1/12 — 13:52 — page 270 — #308 ✐ Capítulo 9. Funciones inline } const std::string& msg = "Requirement failed"){ using namespace std; if (!requirement) { fputs(msg.c_str(), stderr); fputs("\n", stderr); exit(1); } inline void requireArgs(int argc, int args, const std::string& msg = "Must use %d arguments") { using namespace std; if (argc != args + 1) { fprintf(stderr, msg.c_str(), args); fputs("\n", stderr); exit(1); } } inline void requireMinArgs(int argc, int minArgs, const std::string& msg = "Must use at least %d arguments") { using namespace std; if(argc < minArgs + 1) { fprintf(stderr, msg.c_str(), minArgs); fputs("\n", stderr); exit(1); } } inline void assure(std::ifstream& in, const std::string& filename = "") { using namespace std; if(!in) { fprintf(stderr, "Could not open file %s\n", filename.c_str()); exit(1); } } inline void assure(std::ofstream& out, const std::string& filename = "") { using namespace std; if(!out) { fprintf(stderr, "Could not open file %s\n", filename.c_str()); exit(1); } } #endif // REQUIRE_H ///:~ Los valores por defecto proporcionan mensajes razonables que se pueden cambiar si es necesario. Fíjese en que en lugar de usar argumentos char* se utiliza const string&. Esto permite tanto char*, cadenas string como argumentos para estas funciones, y así 270 ✐ ✐ ✐ ✐
✐ ✐ ✐ “Volumen1” — 2012/1/12 — 13:52 — page 271 — #309 ✐ 9.7. Comprobación de errores mejorada es más general (quizá quiera utilizar esta forma en su propio código). En las definiciones para requireArgs() y requireMinArgs(), se añade uno al número de argumentos que necesita en la línea de comandos porque argc siempre incluye el nombre del programa que está ejecutado como argumento cero, y por eso siempre tiene un valor que excede en uno al número real de argumentos de la línea de comandos. Fíjese en el uso de declaraciones locales using namespace std con cada función. Esto es porque algunos compiladores en el momento de escribir este libro incluyen incorrectamente las funciones de la librería C estándar en el espacio de nombres std, así que la cualificación explícita podría causar un error en tiempo de compilación. Las declaraciones locales permiten que require.h funcione tanto con librerías correctas como con incorrectas sin abrir el espacio de nombres std para cualquiera que incluya este fichero de cabecera. Aquí hay un programa simple para probar requite.h: //: C09:ErrTest.cpp //{T} ErrTest.cpp // Testing require.h #include "../require.h" #include using namespace std; int main(int argc, char* argv[]) { int i = 1; require(i, "value must be nonzero"); requireArgs(argc, 1); requireMinArgs(argc, 1); ifstream in(argv[1]); assure(in, argv[1]); // Use the file name ifstream nofile("nofile.xxx"); // Fails: //! assure(nofile); // The default argument ofstream out("tmp.txt"); assure(out); } ///:~ Podría estar tentado a ir un paso más allá para manejar la apertura de ficheros y añadir una macro a require.h. #define IFOPEN(VAR, NAME) \ ifstream VAR(NAME); \ assure(VAR, NAME); Que podría usarse entonces así: IFOPEN(in, argv[1]) En principio, esto podría parecer atractivo porque significa que hay que escribir menos. No es terriblemente inseguro, pero es un camino que es mejor evitar. Fíjese que, de nuevo, una macro parece una función pero se comporta diferente; realmente se está creando un objeto in cuyo alcance persiste más allá de la macro. Quizá lo entienda, pero para programadores nuevos y mantenedores de código sólo es una 271 ✐ ✐ ✐ ✐
- Page 257 and 258: ✐ ✐ ✐ “Volumen1” — 2012
- Page 259 and 260: ✐ ✐ ✐ “Volumen1” — 2012
- Page 261 and 262: ✐ ✐ ✐ “Volumen1” — 2012
- Page 263 and 264: ✐ ✐ ✐ “Volumen1” — 2012
- Page 265 and 266: ✐ ✐ ✐ “Volumen1” — 2012
- Page 267 and 268: ✐ ✐ ✐ “Volumen1” — 2012
- Page 269 and 270: ✐ ✐ ✐ “Volumen1” — 2012
- Page 271 and 272: ✐ ✐ ✐ “Volumen1” — 2012
- Page 273 and 274: ✐ ✐ ✐ “Volumen1” — 2012
- Page 275 and 276: ✐ ✐ ✐ “Volumen1” — 2012
- Page 277 and 278: ✐ ✐ ✐ “Volumen1” — 2012
- Page 279 and 280: ✐ ✐ ✐ “Volumen1” — 2012
- Page 281 and 282: ✐ ✐ ✐ “Volumen1” — 2012
- Page 283 and 284: ✐ ✐ ✐ “Volumen1” — 2012
- Page 285 and 286: ✐ ✐ ✐ “Volumen1” — 2012
- Page 287 and 288: ✐ ✐ ✐ “Volumen1” — 2012
- Page 289 and 290: ✐ ✐ ✐ “Volumen1” — 2012
- Page 291 and 292: ✐ ✐ ✐ “Volumen1” — 2012
- Page 293 and 294: ✐ ✐ ✐ “Volumen1” — 2012
- Page 295 and 296: ✐ ✐ ✐ “Volumen1” — 2012
- Page 297 and 298: ✐ ✐ ✐ “Volumen1” — 2012
- Page 299 and 300: ✐ ✐ ✐ “Volumen1” — 2012
- Page 301 and 302: ✐ ✐ ✐ “Volumen1” — 2012
- Page 303 and 304: ✐ ✐ ✐ “Volumen1” — 2012
- Page 305 and 306: ✐ ✐ ✐ “Volumen1” — 2012
- Page 307: ✐ ✐ ✐ “Volumen1” — 2012
- Page 311 and 312: ✐ ✐ ✐ “Volumen1” — 2012
- Page 313 and 314: ✐ ✐ ✐ “Volumen1” — 2012
- Page 315 and 316: ✐ ✐ ✐ “Volumen1” — 2012
- Page 317 and 318: ✐ ✐ ✐ “Volumen1” — 2012
- Page 319 and 320: ✐ ✐ ✐ “Volumen1” — 2012
- Page 321 and 322: ✐ ✐ ✐ “Volumen1” — 2012
- Page 323 and 324: ✐ ✐ ✐ “Volumen1” — 2012
- Page 325 and 326: ✐ ✐ ✐ “Volumen1” — 2012
- Page 327 and 328: ✐ ✐ ✐ “Volumen1” — 2012
- Page 329 and 330: ✐ ✐ ✐ “Volumen1” — 2012
- Page 331 and 332: ✐ ✐ ✐ “Volumen1” — 2012
- Page 333 and 334: ✐ ✐ ✐ “Volumen1” — 2012
- Page 335 and 336: ✐ ✐ ✐ “Volumen1” — 2012
- Page 337 and 338: ✐ ✐ ✐ “Volumen1” — 2012
- Page 339 and 340: ✐ ✐ ✐ “Volumen1” — 2012
- Page 341 and 342: ✐ ✐ ✐ “Volumen1” — 2012
- Page 343 and 344: ✐ ✐ ✐ “Volumen1” — 2012
- Page 345 and 346: ✐ ✐ ✐ “Volumen1” — 2012
- Page 347 and 348: ✐ ✐ ✐ “Volumen1” — 2012
- Page 349 and 350: ✐ ✐ ✐ “Volumen1” — 2012
- Page 351 and 352: ✐ ✐ ✐ “Volumen1” — 2012
- Page 353 and 354: ✐ ✐ ✐ “Volumen1” — 2012
- Page 355 and 356: ✐ ✐ ✐ “Volumen1” — 2012
- Page 357 and 358: ✐ ✐ ✐ “Volumen1” — 2012
✐<br />
✐<br />
✐<br />
“Volum<strong>en</strong>1” — 2012/1/12 — 13:52 — page 270 — #308<br />
✐<br />
Capítulo 9. Funciones inline<br />
}<br />
const std::string& msg = "Requirem<strong>en</strong>t failed"){<br />
using namespace std;<br />
if (!requirem<strong>en</strong>t) {<br />
fputs(msg.c_str(), stderr);<br />
fputs("\n", stderr);<br />
exit(1);<br />
}<br />
inline void requireArgs(int argc, int args,<br />
const std::string& msg =<br />
"Must use %d argum<strong>en</strong>ts") {<br />
using namespace std;<br />
if (argc != args + 1) {<br />
fprintf(stderr, msg.c_str(), args);<br />
fputs("\n", stderr);<br />
exit(1);<br />
}<br />
}<br />
inline void requireMinArgs(int argc, int minArgs,<br />
const std::string& msg =<br />
"Must use at least %d argum<strong>en</strong>ts") {<br />
using namespace std;<br />
if(argc < minArgs + 1) {<br />
fprintf(stderr, msg.c_str(), minArgs);<br />
fputs("\n", stderr);<br />
exit(1);<br />
}<br />
}<br />
inline void assure(std::ifstream& in,<br />
const std::string& fil<strong>en</strong>ame = "") {<br />
using namespace std;<br />
if(!in) {<br />
fprintf(stderr, "Could not op<strong>en</strong> file %s\n",<br />
fil<strong>en</strong>ame.c_str());<br />
exit(1);<br />
}<br />
}<br />
inline void assure(std::ofstream& out,<br />
const std::string& fil<strong>en</strong>ame = "") {<br />
using namespace std;<br />
if(!out) {<br />
fprintf(stderr, "Could not op<strong>en</strong> file %s\n",<br />
fil<strong>en</strong>ame.c_str());<br />
exit(1);<br />
}<br />
}<br />
#<strong>en</strong>dif // REQUIRE_H ///:~<br />
Los valores por defecto proporcionan m<strong>en</strong>sajes razonables que se pued<strong>en</strong> cambiar<br />
si es necesario.<br />
Fíjese <strong>en</strong> que <strong>en</strong> lugar de usar argum<strong>en</strong>tos char* se utiliza const string&. Esto<br />
permite tanto char*, cad<strong>en</strong>as string como argum<strong>en</strong>tos para estas funciones, y así<br />
270<br />
✐<br />
✐<br />
✐<br />
✐