Pensar en C++ (Volumen 1) - Grupo ARCO

Pensar en C++ (Volumen 1) - Grupo ARCO Pensar en C++ (Volumen 1) - Grupo ARCO

arco.esi.uclm.es
from arco.esi.uclm.es More from this publisher
13.01.2015 Views

✐ ✐ ✐ “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 ✐ ✐ ✐ ✐

✐<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 />

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!