2009-03-29 21 views
5

Quando si utilizza la macro BOOST_SERIALIZATION_NVP per creare una coppia nome-valore per la serializzazione XML, il compilatore felicemente consente la compilazione del seguente codice, anche se il nome dell'elemento non è un XML valido elemento e un eccezioni viene generata quando cercando di serializzare in realtà l'oggetto in XML:boost serialization Caratteri NVP macro e caratteri non XML

BOOST_SERIALIZATION_NVP(_member[index]) 

una correzione evidente è quello di utilizzare:

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

Ma qualcuno può suggerire un modo per modificare spinta in modo che elemento illegittimo i nomi attiverebbero una compilazione n errore? (Quindi non basandosi su test di unità per prendere il sopra sottili bug)


Edit:

Un'idea è quella di dichiarare in qualche modo una variabile locale fittizio con il nome dell'elemento passato alla macro, supponendo che l'insieme di identificatori validi in C++ sia un sottoinsieme di elementi XML validi. Non è sicuro che tutto ciò possa essere fatto.

+0

Questo genererà un errore di runtime 'what(): Nome tag XML non valido ' – alfC

risposta

1

Penso che la tua idea probabilmente funzionerà. Gli identificatori C++ validi sono costituiti da A-Z, a-z, 0-9 e underscore, che è in effetti un sottoinsieme appropriato di identificatori XML (che aggiungono il trattino, il punto e un gruppo di caratteri Unicode al set).

Si potrebbe provare un costrutto come questo per ottenere un errore di compilazione:

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

Le parentesi limitare l'ambito della variabile dummy a poco quella linea, in modo da non ingombrare la vostra funzione con variabili fasulli . Probabilmente il compilatore ottimizza anche la variabile dummy, quindi non ci sono costi di runtime. Quando uso questa macro nel seguente codice, ottengo 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; 
} 

Se sostituisco foo[0] con bar nella chiamata a SAFE_BOOST_SERIALIZATION_NVP, compila senza errori.

+1

Ma non penso che funzionerebbe se usato nella funzione serialize. serialize (..) {archive & SAFE_BOOST_SER_NVP (m); } ... –

+0

@AssafLavie, hai ragione, tuttavia questa leggera modifica (codice extra alla fine) sembra fare il lavoro: '#define SAFE_BOOST_SERIALIZATION_NVP (nome) \ BOOST_SERIALIZATION_NVP (nome); {int name = 0;} ' – alfC

2

Citando la sintassi XML per i nomi:

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] 

vedo le seguenti differenze con nomi C++: Leading _ possono essere prenotati in C++, a seconda di quanto segue; i due punti, i punti e i segni meno sono validi nei nomi XML. I caratteri Unicode possono anche causare qualche problema in C++, ma per lo più dipende dall'implementazione.

La parte [# x0300- # x036F] combina gli accenti (diacritici), che potrebbero costituire un'ulteriore preoccupazione per l'uguaglianza dei nomi.

Quindi, non esiste una soluzione che catturi i caratteri non alfabetici. < ::: /> può sembrare uno smiley, ma è un XML ben formato. Per il resto, la tua idea è praticamente OK. L'idea di Eric Melski è un bel tentativo, ma accetta molti caratteri non alfabetici. Ad esempio, foo[1], &foo, *foo, foo=0 o foo,bar. C'è un'alternativa migliore: {using namespace name;}. Questo accetterà foo::bar, ma in realtà è OK - foo :: bar è consentito in XML.

+0

Ma se il' nome' non è già un namespace, verrà generato un errore. – alfC

1

Questo è un ibrido tra due risposte, @Eric Melski (per lo più corretto - il codiceextra deve essere alla fine di define - ma una soluzione incompleta - alcuni nomi proibiti non sono "filtrati" -) e @MSalters " per lo più corretto (- using namespace non può essere utilizzato per nomi arbitrari non dichiarati--).

propongo utilizzando struct:

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

o più rischioso:

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

Inutile dire che non ci sono costi di runtime per questo.