2009-03-29 7 views
5

Al usar la macro BOOST_SERIALIZATION_NVP para crear un par nombre-valor para la serialización XML, el compilador permite compilar sin problemas el siguiente código, aunque el nombre del elemento no sea un XML válido elemento y un excepciones se inicia cuando intenta serializar en realidad el objeto en XML:serialización de refuerzo Caracteres NVP macro y no XML

BOOST_SERIALIZATION_NVP(_member[index]) 

una solución obvia es usar:

boost::serialization::make_nvp("ValidMemberName", _member[index]) 

Pero puede alguien sugerir una manera de modificar impulso de manera que el elemento ilegítima nombres desencadenarían una compilación n error? (Por lo tanto no depender de las pruebas unitarias para coger el anterior error sutil)


Editar:

Una idea es declarar de alguna manera una variable local maniquí con el nombre del elemento pasado a la macro, asumiendo que el conjunto de identificadores válidos en C++ es un subconjunto de elementos XML válidos. Sin embargo, no estoy seguro de que esto pueda hacerse.

+0

Esto generará un error de tiempo de ejecución 'what(): nombre de etiqueta XML no válido' – alfC

Respuesta

1

Creo que su idea probablemente funcione. Los identificadores válidos de C++ están formados por A-Z, a-z, 0-9 y guión bajo, que de hecho es un subconjunto apropiado de identificadores XML (que añaden guión, punto y un montón de caracteres Unicode al conjunto).

Usted podría tratar de una construcción como esta para obtener un error de tiempo de compilación:

#define SAFE_BOOST_SERIALIZATION_NVP(name) \ 
    { int name = 0; } ; BOOST_SERIALZATION_NVP(name) 

Los apoyos limitar el alcance de la variable ficticia que solo esa línea, por lo que no estorba su función con variables ficticias . Probablemente, el compilador también optimiza la variable ficticia, por lo que no hay costo de tiempo de ejecución. Cuando utilizo esta macro en el código siguiente, consigo error: invalid intializer:

#include "boost/serialization/nvp.hpp" 
#define SAFE_BOOST_SERIALIZATION_NVP(name) \ 
    { int name = 0; } ; BOOST_SERIALIZATION_NVP(name) 

int main(int argc, char *argv[]) 
{ 
    int foo[3] = { 10, 20, 30 }; 
    int bar = 10; 
    SAFE_BOOST_SERIALIZATION_NVP(foo[0]); 
    return 0; 
} 

Si sustituyo foo[0] con bar en la llamada a SAFE_BOOST_SERIALIZATION_NVP, compila sin error.

+1

Pero no creo que funcione cuando se usa en la función serializar. serialize (..) {archive & SAFE_BOOST_SER_NVP (m); } ... –

+0

@AssafLavie, tiene razón, sin embargo, esta ligera modificación (código adicional al final) parece hacer el trabajo: '#define SAFE_BOOST_SERIALIZATION_NVP (name) \ BOOST_SERIALIZATION_NVP (name); {int name = 0;} ' – alfC

2

Citando la sintaxis XML para nombres:

NameStartChar ::= ":" | [A-Z] | "_" | [a-z] | [#xC0-#xD6] | [#xD8-#xF6] | [#xF8-#x2FF] | [#x370-#x37D] | [#x37F-#x1FFF] | [#x200C-#x200D] | [#x2070-#x218F] | [#x2C00-#x2FEF] | [#x3001-#xD7FF] | [#xF900-#xFDCF] | [#xFDF0-#xFFFD] | [#x10000-#xEFFFF] 
NameChar  ::= NameStartChar | "-" | "." | [0-9] | #xB7 | [#x0300-#x036F] | [#x203F-#x2040] 

veo las siguientes diferencias con los nombres de C++: Leading _ puede ser reservada en C++, dependiendo de lo que sigue; dos puntos y signos menos son válidos en nombres XML. Los caracteres Unicode también pueden causar algo de dolor en C++, pero eso depende principalmente de la implementación.

La parte [# x0300- # x036F] combina acentos (diacríticos), lo que podría ser una preocupación adicional con respecto a la igualdad de nombres.

Por lo tanto, no hay ninguna solución que atrape los caracteres no alfabéticos. < ::: /> puede parecer un emoticón, pero es un XML bien formado. Por lo demás, tu idea está bastante bien. La idea de Eric Melski es un buen intento, pero acepta muchos caracteres no alfabéticos. Por ejemplo, foo[1], &foo, *foo, foo=0 o foo,bar. Hay una mejor alternativa: {using namespace name;}. Esto aceptará foo::bar, pero eso está realmente bien - foo :: bar está permitido en XML.

+0

Pero si el' nombre' no es ya un espacio de nombres, dará un error. – alfC

1

Esto es un híbrido entre dos respuestas, @Eric Melski (en su mayoría correcto --extra código debe estar al final de define-- pero solución incompleta --algunos nombres prohibidos no están "filtrados" -) y @MSalters ' la mayoría de las veces correctas (- using namespace no pueden usarse para nombres arbitrarios no declarados--).

propongo utilizando struct:

#define SAFE_BOOST_SERIALIZATION_NVP(name) \ 
    BOOST_SERIALIZATION_NVP(name); {struct name{};} 

o más arriesgada:

#undef BOOST_SERIALIZATION_NVP 
#define BOOST_SERIALIZATION_NVP(name)        \ 
    boost::serialization::make_nvp(BOOST_PP_STRINGIZE(name), name); {struct name{};} 

No hace falta decir que no hay ningún costo para este tiempo de ejecución.